FileDocCategorySizeDatePackage
CSS.javaAPI DocJava SE 5 API100272Fri Aug 26 14:58:18 BST 2005javax.swing.text.html

CSS

public class CSS extends Object implements Serializable
Defines a set of CSS attributes as a typesafe enumeration. The HTML View implementations use CSS attributes to determine how they will render. This also defines methods to map between CSS/HTML/StyleConstants. Any shorthand properties, such as font, are mapped to the intrinsic properties.

The following describes the CSS properties that are suppored by the rendering engine:

  • font-family
  • font-style
  • font-size (supports relative units)
  • font-weight
  • font
  • color
  • background-color (with the exception of transparent)
  • background-image
  • background-repeat
  • background-position
  • background
  • background-repeat
  • text-decoration (with the exception of blink and overline)
  • vertical-align (only sup and super)
  • text-align (justify is treated as center)
  • margin-top
  • margin-right
  • margin-bottom
  • margin-left
  • margin
  • padding-top
  • padding-right
  • padding-bottom
  • padding-left
  • border-style (only supports inset, outset and none)
  • list-style-type
  • list-style-position
The following are modeled, but currently not rendered.
  • font-variant
  • background-attachment (background always treated as scroll)
  • word-spacing
  • letter-spacing
  • text-indent
  • text-transform
  • line-height
  • border-top-width (this is used to indicate if a border should be used)
  • border-right-width
  • border-bottom-width
  • border-left-width
  • border-width
  • border-top
  • border-right
  • border-bottom
  • border-left
  • border
  • width
  • height
  • float
  • clear
  • display
  • white-space
  • list-style

Note: for the time being we do not fully support relative units, unless noted, so that p { margin-top: 10% } will be treated as if no margin-top was specified.

author
Timothy Prinzing
author
Scott Violet
version
1.57 09/15/04
see
StyleSheet

Fields Summary
private static final Hashtable
attributeMap
private static final Hashtable
valueMap
private static final Hashtable
htmlAttrToCssAttrMap
The hashtable and the static initalization block below, set up a mapping from well-known HTML attributes to CSS attributes. For the most part, there is a 1-1 mapping between the two. However in the case of certain HTML attributes for example HTML.Attribute.VSPACE or HTML.Attribute.HSPACE, end up mapping to two CSS.Attribute's. Therefore, the value associated with each HTML.Attribute. key ends up being an array of CSS.Attribute.* objects.
private static final Hashtable
styleConstantToCssMap
The hashtable and static initialization that follows sets up a translation from StyleConstants (i.e. the well known attributes) to the associated CSS attributes.
private static final Hashtable
htmlValueToCssValueMap
Maps from HTML value to a CSS value. Used in internal mapping.
private static final Hashtable
cssValueToInternalValueMap
Maps from CSS value (string) to internal value.
private static Hashtable
fontMapping
Used to indicate if a font family name is valid.
private transient Hashtable
valueConvertor
Maps from CSS key to CssValue.
private int
baseFontSize
Size used for relative units.
private transient StyleSheet
styleSheet
static int
baseFontSizeIndex
Constructors Summary
public CSS()

    

      
	baseFontSize = baseFontSizeIndex + 1;
	// setup the css conversion table
	valueConvertor = new Hashtable();
	valueConvertor.put(CSS.Attribute.FONT_SIZE, new FontSize());
	valueConvertor.put(CSS.Attribute.FONT_FAMILY, new FontFamily());
	valueConvertor.put(CSS.Attribute.FONT_WEIGHT, new FontWeight());
	valueConvertor.put(CSS.Attribute.BORDER_STYLE, new BorderStyle());
	Object cv = new ColorValue();
	valueConvertor.put(CSS.Attribute.COLOR, cv);
	valueConvertor.put(CSS.Attribute.BACKGROUND_COLOR, cv);
	valueConvertor.put(CSS.Attribute.BORDER_COLOR, cv);
	Object lv = new LengthValue();
	valueConvertor.put(CSS.Attribute.MARGIN_TOP, lv);
	valueConvertor.put(CSS.Attribute.MARGIN_BOTTOM, lv);
	valueConvertor.put(CSS.Attribute.MARGIN_LEFT, lv);
        valueConvertor.put(CSS.Attribute.MARGIN_LEFT_LTR, lv);
        valueConvertor.put(CSS.Attribute.MARGIN_LEFT_RTL, lv);
	valueConvertor.put(CSS.Attribute.MARGIN_RIGHT, lv);
        valueConvertor.put(CSS.Attribute.MARGIN_RIGHT_LTR, lv);
        valueConvertor.put(CSS.Attribute.MARGIN_RIGHT_RTL, lv);
	valueConvertor.put(CSS.Attribute.PADDING_TOP, lv);
	valueConvertor.put(CSS.Attribute.PADDING_BOTTOM, lv);
	valueConvertor.put(CSS.Attribute.PADDING_LEFT, lv);
	valueConvertor.put(CSS.Attribute.PADDING_RIGHT, lv);
	Object bv = new BorderWidthValue(null, 0);
	valueConvertor.put(CSS.Attribute.BORDER_WIDTH, lv);
	valueConvertor.put(CSS.Attribute.BORDER_TOP_WIDTH, bv);
	valueConvertor.put(CSS.Attribute.BORDER_BOTTOM_WIDTH, bv);
	valueConvertor.put(CSS.Attribute.BORDER_LEFT_WIDTH, bv);
	valueConvertor.put(CSS.Attribute.BORDER_RIGHT_WIDTH, bv);
	Object nlv = new LengthValue(true);
	valueConvertor.put(CSS.Attribute.TEXT_INDENT, nlv);
	valueConvertor.put(CSS.Attribute.WIDTH, lv);
	valueConvertor.put(CSS.Attribute.HEIGHT, lv);
	valueConvertor.put(CSS.Attribute.BORDER_SPACING, lv);
	Object sv = new StringValue();
	valueConvertor.put(CSS.Attribute.FONT_STYLE, sv);
	valueConvertor.put(CSS.Attribute.TEXT_DECORATION, sv);
	valueConvertor.put(CSS.Attribute.TEXT_ALIGN, sv);
	valueConvertor.put(CSS.Attribute.VERTICAL_ALIGN, sv);
	Object valueMapper = new CssValueMapper();
	valueConvertor.put(CSS.Attribute.LIST_STYLE_TYPE,
			   valueMapper);
	valueConvertor.put(CSS.Attribute.BACKGROUND_IMAGE,
			   new BackgroundImage());
	valueConvertor.put(CSS.Attribute.BACKGROUND_POSITION,
			   new BackgroundPosition());
	valueConvertor.put(CSS.Attribute.BACKGROUND_REPEAT,
			   valueMapper);
	valueConvertor.put(CSS.Attribute.BACKGROUND_ATTACHMENT,
			   valueMapper);
	Object generic = new CssValue();
	int n = CSS.Attribute.allAttributes.length;
	for (int i = 0; i < n; i++) {
	    CSS.Attribute key = CSS.Attribute.allAttributes[i];
	    if (valueConvertor.get(key) == null) {
		valueConvertor.put(key, generic);
	    }
	}
    
Methods Summary
voidaddInternalCSSValue(javax.swing.text.MutableAttributeSet attr, javax.swing.text.html.CSS$Attribute key, java.lang.String value)
Parses the CSS property key with value value placing the result in att.

	if (key == CSS.Attribute.FONT) {
	    ShorthandFontParser.parseShorthandFont(this, value, attr);
	}
	else if (key == CSS.Attribute.BACKGROUND) {
	    ShorthandBackgroundParser.parseShorthandBackground
		               (this, value, attr);
	}
	else if (key == CSS.Attribute.MARGIN) {
	    ShorthandMarginParser.parseShorthandMargin(this, value, attr,
					   CSS.Attribute.ALL_MARGINS);
	}
	else if (key == CSS.Attribute.PADDING) {
	    ShorthandMarginParser.parseShorthandMargin(this, value, attr,
					   CSS.Attribute.ALL_PADDING);
	}
	else if (key == CSS.Attribute.BORDER_WIDTH) {
	    ShorthandMarginParser.parseShorthandMargin(this, value, attr,
					   CSS.Attribute.ALL_BORDER_WIDTHS);
	}
	else {
	    Object iValue = getInternalCSSValue(key, value);
	    if (iValue != null) {
		attr.addAttribute(key, iValue);
	    }
	}
    
static voidcalculateTiledLayout(javax.swing.text.html.CSS$LayoutIterator iter, int targetSpan)
Calculate a tiled layout for the given iterator. This should be done collapsing the neighboring margins to be a total of the maximum of the two neighboring margin areas as described in the CSS spec.

	
	/*
	 * first pass, calculate the preferred sizes, adjustments needed because
	 * of margin collapsing, and the flexibility to adjust the sizes.
	 */
	long preferred = 0;
	long currentPreferred = 0;
	int lastMargin = 0;
	int totalSpacing = 0;
	int n = iter.getCount();
	int adjustmentWeightsCount = LayoutIterator.WorstAdjustmentWeight + 1;
	//max gain we can get adjusting elements with adjustmentWeight <= i
	long gain[] = new long[adjustmentWeightsCount]; 
	//max loss we can get adjusting elements with adjustmentWeight <= i
	long loss[] = new long[adjustmentWeightsCount]; 

	for (int i = 0; i < adjustmentWeightsCount; i++) {
	    gain[i] = loss[i] = 0;
	}
	for (int i = 0; i < n; i++) {
	    iter.setIndex(i);
	    int margin0 = lastMargin;
	    int margin1 = (int) iter.getLeadingCollapseSpan();

	    iter.setOffset(Math.max(margin0, margin1));
	    totalSpacing += iter.getOffset();

	    currentPreferred = (long)iter.getPreferredSpan(targetSpan);
	    iter.setSpan((int) currentPreferred);
	    preferred += currentPreferred;
	    gain[iter.getAdjustmentWeight()] += 
		(long)iter.getMaximumSpan(targetSpan) - currentPreferred;
	    loss[iter.getAdjustmentWeight()] += 
		currentPreferred - (long)iter.getMinimumSpan(targetSpan);
	    lastMargin = (int) iter.getTrailingCollapseSpan();
	}
	totalSpacing += lastMargin;               
	totalSpacing += 2 * iter.getBorderWidth();	
	
	for (int i = 1; i < adjustmentWeightsCount; i++) {
	    gain[i] += gain[i - 1];
	    loss[i] += loss[i - 1];
	}

	/*
	 * Second pass, expand or contract by as much as possible to reach
	 * the target span.  This takes the margin collapsing into account
	 * prior to adjusting the span.
	 */

	// determine the adjustment to be made
	int allocated = targetSpan - totalSpacing;
	long desiredAdjustment = allocated - preferred;
	long adjustmentsArray[] = (desiredAdjustment > 0) ? gain : loss;
	desiredAdjustment = Math.abs(desiredAdjustment);
	int adjustmentLevel = 0;
	for (;adjustmentLevel <= LayoutIterator.WorstAdjustmentWeight; 
	     adjustmentLevel++) { 
	    // adjustmentsArray[] is sorted. I do not bother about
	    // binary search though
	    if (adjustmentsArray[adjustmentLevel] >= desiredAdjustment) {
		break;
	    }
	}
	float adjustmentFactor = 0.0f;
	if (adjustmentLevel <= LayoutIterator.WorstAdjustmentWeight) {
	    desiredAdjustment -= (adjustmentLevel > 0) ? 
		adjustmentsArray[adjustmentLevel - 1] : 0;
	    if (desiredAdjustment != 0) {
		float maximumAdjustment = 
		    adjustmentsArray[adjustmentLevel] - 
		    ((adjustmentLevel > 0) ? 
		     adjustmentsArray[adjustmentLevel - 1] : 0
		     );
		adjustmentFactor = desiredAdjustment / maximumAdjustment;
	    }
	}
	// make the adjustments
	int totalOffset = (int)iter.getBorderWidth();;
	for (int i = 0; i < n; i++) {
	    iter.setIndex(i);
	    iter.setOffset( iter.getOffset() + totalOffset);
	    if (iter.getAdjustmentWeight() < adjustmentLevel) {
		iter.setSpan((int)
			     ((allocated > preferred) ? 
			      Math.floor(iter.getMaximumSpan(targetSpan)) : 
			      Math.ceil(iter.getMinimumSpan(targetSpan))
			      )
			     );
	    } else if (iter.getAdjustmentWeight() == adjustmentLevel) {
		int availableSpan = (allocated > preferred) ? 
		    (int) iter.getMaximumSpan(targetSpan) - iter.getSpan() : 
		    iter.getSpan() - (int) iter.getMinimumSpan(targetSpan);
		int adj = (int)Math.floor(adjustmentFactor * availableSpan);
		iter.setSpan(iter.getSpan() + 
			     ((allocated > preferred) ? adj : -adj));
	    }
	    totalOffset = (int) Math.min((long) iter.getOffset() + 
					 (long) iter.getSpan(), 
					 Integer.MAX_VALUE);
	}

	// while rounding we could lose several pixels.
        int roundError = targetSpan - totalOffset - 
	    (int)iter.getTrailingCollapseSpan() - 
	    (int)iter.getBorderWidth();
	int adj = (roundError > 0) ? 1 : -1;
	roundError *= adj;

        boolean canAdjust = true;
        while (roundError > 0 && canAdjust) {
	    // check for infinite loop
	    canAdjust = false;
	    int offsetAdjust = 0;
	    // try to distribute roundError. one pixel per cell
	    for (int i = 0; i < n; i++) {
		iter.setIndex(i);
		iter.setOffset(iter.getOffset() + offsetAdjust);
                int curSpan = iter.getSpan();
                if (roundError > 0) {
		    int boundGap = (adj > 0) ? 
			(int)Math.floor(iter.getMaximumSpan(targetSpan)) - curSpan : 
			curSpan - (int)Math.ceil(iter.getMinimumSpan(targetSpan));
		    if (boundGap >= 1) {
			canAdjust = true;
			iter.setSpan(curSpan + adj);
			offsetAdjust += adj;
			roundError--;
		    }
                }
	    }
	}
    
static javax.swing.SizeRequirementscalculateTiledRequirements(javax.swing.text.html.CSS$LayoutIterator iter, javax.swing.SizeRequirements r)
Calculate the requirements needed to tile the requirements given by the iterator that would be tiled. The calculation takes into consideration margin and border spacing.

	long minimum = 0;
	long maximum = 0;
	long preferred = 0;
	int lastMargin = 0;
	int totalSpacing = 0;
	int n = iter.getCount();
	for (int i = 0; i < n; i++) {
	    iter.setIndex(i);
	    int margin0 = lastMargin;
	    int margin1 = (int) iter.getLeadingCollapseSpan();
	    totalSpacing += Math.max(margin0, margin1);;
	    preferred += (int) iter.getPreferredSpan(0);
	    minimum += iter.getMinimumSpan(0);
	    maximum += iter.getMaximumSpan(0);

	    lastMargin = (int) iter.getTrailingCollapseSpan();
	}
	totalSpacing += lastMargin;
	totalSpacing += 2 * iter.getBorderWidth();

	// adjust for the spacing area
	minimum += totalSpacing;
	preferred += totalSpacing;
	maximum += totalSpacing;

	// set return value
	if (r == null) {
	    r = new SizeRequirements();
	}
	r.minimum = (minimum > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)minimum;
	r.preferred = (preferred > Integer.MAX_VALUE) ? Integer.MAX_VALUE :(int) preferred;
	r.maximum = (maximum > Integer.MAX_VALUE) ? Integer.MAX_VALUE :(int) maximum;
	return r;
    
static java.lang.StringcolorToHex(java.awt.Color color)
Converts a type Color to a hex string in the format "#RRGGBB"


      String colorstr = new String("#");

      // Red
      String str = Integer.toHexString(color.getRed());
      if (str.length() > 2)
	str = str.substring(0, 2);
      else if (str.length() < 2)
	colorstr += "0" + str;
      else
	colorstr += str;

      // Green
      str = Integer.toHexString(color.getGreen());
      if (str.length() > 2)
	str = str.substring(0, 2);
      else if (str.length() < 2)
	colorstr += "0" + str;
      else
	colorstr += str;

      // Blue
      str = Integer.toHexString(color.getBlue());
      if (str.length() > 2)
	str = str.substring(0, 2);
      else if (str.length() < 2)
	colorstr += "0" + str;
      else
	colorstr += str;

      return colorstr;
    
java.lang.ObjectcssValueToStyleConstantsValue(javax.swing.text.StyleConstants key, java.lang.Object value)
Converts the passed in CSS value to a StyleConstants value. key identifies the CSS attribute being mapped.

	if (value instanceof CssValue) {
	    return ((CssValue)value).toStyleConstants((StyleConstants)key,
						      null);
	}
	return null;
    
public static javax.swing.text.html.CSS$Attribute[]getAllAttributeKeys()
Return the set of all possible CSS attribute keys.


     
	// load the attribute map
	for (int i = 0; i < Attribute.allAttributes.length; i++ ) {
	    attributeMap.put(Attribute.allAttributes[i].toString(),
			     Attribute.allAttributes[i]);
	}
	// load the value map
	for (int i = 0; i < Value.allValues.length; i++ ) {
	    valueMap.put(Value.allValues[i].toString(), 
			     Value.allValues[i]);
	}

	htmlAttrToCssAttrMap.put(HTML.Attribute.COLOR,
				 new CSS.Attribute[]{CSS.Attribute.COLOR});
	htmlAttrToCssAttrMap.put(HTML.Attribute.TEXT,
				 new CSS.Attribute[]{CSS.Attribute.COLOR});
	htmlAttrToCssAttrMap.put(HTML.Attribute.CLEAR,
				 new CSS.Attribute[]{CSS.Attribute.CLEAR});
	htmlAttrToCssAttrMap.put(HTML.Attribute.BACKGROUND,
				 new CSS.Attribute[]{CSS.Attribute.BACKGROUND_IMAGE});
	htmlAttrToCssAttrMap.put(HTML.Attribute.BGCOLOR,
				 new CSS.Attribute[]{CSS.Attribute.BACKGROUND_COLOR});
	htmlAttrToCssAttrMap.put(HTML.Attribute.WIDTH,
				 new CSS.Attribute[]{CSS.Attribute.WIDTH});
	htmlAttrToCssAttrMap.put(HTML.Attribute.HEIGHT,
				 new CSS.Attribute[]{CSS.Attribute.HEIGHT});
	htmlAttrToCssAttrMap.put(HTML.Attribute.BORDER,
				 new CSS.Attribute[]{CSS.Attribute.BORDER_TOP_WIDTH, CSS.Attribute.BORDER_RIGHT_WIDTH, CSS.Attribute.BORDER_BOTTOM_WIDTH, CSS.Attribute.BORDER_LEFT_WIDTH});
	htmlAttrToCssAttrMap.put(HTML.Attribute.CELLPADDING,
				 new CSS.Attribute[]{CSS.Attribute.PADDING});
	htmlAttrToCssAttrMap.put(HTML.Attribute.CELLSPACING,
				 new CSS.Attribute[]{CSS.Attribute.BORDER_SPACING});
	htmlAttrToCssAttrMap.put(HTML.Attribute.MARGINWIDTH,
				 new CSS.Attribute[]{CSS.Attribute.MARGIN_LEFT,
						     CSS.Attribute.MARGIN_RIGHT});
	htmlAttrToCssAttrMap.put(HTML.Attribute.MARGINHEIGHT,
				 new CSS.Attribute[]{CSS.Attribute.MARGIN_TOP,
						     CSS.Attribute.MARGIN_BOTTOM});
	htmlAttrToCssAttrMap.put(HTML.Attribute.HSPACE,
				 new CSS.Attribute[]{CSS.Attribute.PADDING_LEFT,
						     CSS.Attribute.PADDING_RIGHT});
	htmlAttrToCssAttrMap.put(HTML.Attribute.VSPACE,
				 new CSS.Attribute[]{CSS.Attribute.PADDING_BOTTOM,
						     CSS.Attribute.PADDING_TOP});
	htmlAttrToCssAttrMap.put(HTML.Attribute.FACE,
				 new CSS.Attribute[]{CSS.Attribute.FONT_FAMILY});
	htmlAttrToCssAttrMap.put(HTML.Attribute.SIZE,
				 new CSS.Attribute[]{CSS.Attribute.FONT_SIZE});
	htmlAttrToCssAttrMap.put(HTML.Attribute.VALIGN,
				 new CSS.Attribute[]{CSS.Attribute.VERTICAL_ALIGN});
	htmlAttrToCssAttrMap.put(HTML.Attribute.ALIGN,
				 new CSS.Attribute[]{CSS.Attribute.VERTICAL_ALIGN,
						     CSS.Attribute.TEXT_ALIGN,
						     CSS.Attribute.FLOAT});
	htmlAttrToCssAttrMap.put(HTML.Attribute.TYPE,
				 new CSS.Attribute[]{CSS.Attribute.LIST_STYLE_TYPE});
	htmlAttrToCssAttrMap.put(HTML.Attribute.NOWRAP,
				 new CSS.Attribute[]{CSS.Attribute.WHITE_SPACE});

	// initialize StyleConstants mapping 
	styleConstantToCssMap.put(StyleConstants.FontFamily, 
				  CSS.Attribute.FONT_FAMILY);
	styleConstantToCssMap.put(StyleConstants.FontSize, 
				  CSS.Attribute.FONT_SIZE);
	styleConstantToCssMap.put(StyleConstants.Bold, 
				  CSS.Attribute.FONT_WEIGHT);
	styleConstantToCssMap.put(StyleConstants.Italic, 
				  CSS.Attribute.FONT_STYLE);
	styleConstantToCssMap.put(StyleConstants.Underline, 
				  CSS.Attribute.TEXT_DECORATION);
	styleConstantToCssMap.put(StyleConstants.StrikeThrough, 
				  CSS.Attribute.TEXT_DECORATION);
	styleConstantToCssMap.put(StyleConstants.Superscript, 
				  CSS.Attribute.VERTICAL_ALIGN);
	styleConstantToCssMap.put(StyleConstants.Subscript, 
				  CSS.Attribute.VERTICAL_ALIGN);
	styleConstantToCssMap.put(StyleConstants.Foreground, 
				  CSS.Attribute.COLOR);
	styleConstantToCssMap.put(StyleConstants.Background, 
				  CSS.Attribute.BACKGROUND_COLOR);
	styleConstantToCssMap.put(StyleConstants.FirstLineIndent, 
				  CSS.Attribute.TEXT_INDENT);
	styleConstantToCssMap.put(StyleConstants.LeftIndent, 
				  CSS.Attribute.MARGIN_LEFT);
	styleConstantToCssMap.put(StyleConstants.RightIndent, 
				  CSS.Attribute.MARGIN_RIGHT);
	styleConstantToCssMap.put(StyleConstants.SpaceAbove, 
				  CSS.Attribute.MARGIN_TOP);
	styleConstantToCssMap.put(StyleConstants.SpaceBelow, 
				  CSS.Attribute.MARGIN_BOTTOM);
	styleConstantToCssMap.put(StyleConstants.Alignment, 
				  CSS.Attribute.TEXT_ALIGN);

	// HTML->CSS
	htmlValueToCssValueMap.put("disc", CSS.Value.DISC);
	htmlValueToCssValueMap.put("square", CSS.Value.SQUARE);
	htmlValueToCssValueMap.put("circle", CSS.Value.CIRCLE);
	htmlValueToCssValueMap.put("1", CSS.Value.DECIMAL);
	htmlValueToCssValueMap.put("a", CSS.Value.LOWER_ALPHA);
	htmlValueToCssValueMap.put("A", CSS.Value.UPPER_ALPHA);
	htmlValueToCssValueMap.put("i", CSS.Value.LOWER_ROMAN);
	htmlValueToCssValueMap.put("I", CSS.Value.UPPER_ROMAN);

	// CSS-> internal CSS
	cssValueToInternalValueMap.put("none", CSS.Value.NONE);
	cssValueToInternalValueMap.put("disc", CSS.Value.DISC);
	cssValueToInternalValueMap.put("square", CSS.Value.SQUARE);
	cssValueToInternalValueMap.put("circle", CSS.Value.CIRCLE);
	cssValueToInternalValueMap.put("decimal", CSS.Value.DECIMAL);
	cssValueToInternalValueMap.put("lower-roman", CSS.Value.LOWER_ROMAN);
	cssValueToInternalValueMap.put("upper-roman", CSS.Value.UPPER_ROMAN);
	cssValueToInternalValueMap.put("lower-alpha", CSS.Value.LOWER_ALPHA);
	cssValueToInternalValueMap.put("upper-alpha", CSS.Value.UPPER_ALPHA);
	cssValueToInternalValueMap.put("repeat", CSS.Value.BACKGROUND_REPEAT);
	cssValueToInternalValueMap.put("no-repeat",
				       CSS.Value.BACKGROUND_NO_REPEAT);
	cssValueToInternalValueMap.put("repeat-x",
				       CSS.Value.BACKGROUND_REPEAT_X);
	cssValueToInternalValueMap.put("repeat-y",
				       CSS.Value.BACKGROUND_REPEAT_Y);
	cssValueToInternalValueMap.put("scroll",
				       CSS.Value.BACKGROUND_SCROLL);
	cssValueToInternalValueMap.put("fixed",
				       CSS.Value.BACKGROUND_FIXED);

        // Register all the CSS attribute keys for archival/unarchival
	Object[] keys = CSS.Attribute.allAttributes;
	try {
	    for (int i = 0; i < keys.length; i++) {
		StyleContext.registerStaticAttributeKey(keys[i]);
	    }
	} catch (Throwable e) {
	    e.printStackTrace();
	}

        // Register all the CSS Values for archival/unarchival
	keys = CSS.Value.allValues;
	try {
	    for (int i = 0; i < keys.length; i++) {
		StyleContext.registerStaticAttributeKey(keys[i]);
	    }
	} catch (Throwable e) {
	    e.printStackTrace();
	}
    
	Attribute[] keys = new Attribute[Attribute.allAttributes.length];
	System.arraycopy(Attribute.allAttributes, 0, keys, 0, Attribute.allAttributes.length);
	return keys;
    
public static final javax.swing.text.html.CSS$AttributegetAttribute(java.lang.String name)
Translates a string to a CSS.Attribute object. This will return null if there is no attribute by the given name.

param
name the name of the CSS attribute to fetch the typesafe enumeration for
return
the CSS.Attribute object, or null if the string doesn't represent a valid attribute key

	return (Attribute) attributeMap.get(name);
    
intgetBaseFontSize()
Returns the base font size.

	return baseFontSize;
    
java.awt.ColorgetColor(javax.swing.text.AttributeSet a, javax.swing.text.html.CSS$Attribute key)
Takes a set of attributes and turn it into a color specification. This might be used to specify things like brighter, more hue, etc. This will return null if there is no value for key.

param
key CSS.Attribute identifying where color is stored.
param
a the set of attributes
return
the color

	ColorValue cv = (ColorValue) a.getAttribute(key);
	if (cv != null) {
	    return cv.getValue();
	}
	return null;
    
private static intgetColorComponent(java.lang.String string, int[] index)
Returns the next integer value from string starting at index[0]. The value can either can an integer, or a percentage (floating number ending with %), in which case it is multiplied by 255.

        int length = string.length();
        char aChar;

        // Skip non-decimal chars
        while(index[0] < length && (aChar = string.charAt(index[0])) != '-" &&
              !Character.isDigit(aChar) && aChar != '.") {
            index[0]++;
        }

        int start = index[0];

        if (start < length && string.charAt(index[0]) == '-") {
            index[0]++;
        }
        while(index[0] < length &&
                         Character.isDigit(string.charAt(index[0]))) {
            index[0]++;
        }
        if (index[0] < length && string.charAt(index[0]) == '.") {
            // Decimal value
            index[0]++;
            while(index[0] < length &&
                  Character.isDigit(string.charAt(index[0]))) {
                index[0]++;
            }
        }
        if (start != index[0]) {
            try {
                float value = Float.parseFloat(string.substring
                                               (start, index[0]));

                if (index[0] < length && string.charAt(index[0]) == '%") {
                    index[0]++;
                    value = value * 255f / 100f;
                }
                return Math.min(255, Math.max(0, (int)value));
            } catch (NumberFormatException nfe) {
                // Treat as 0
            }
        }
        return 0;
    
private javax.swing.text.html.CSS$AttributegetCssAlignAttribute(javax.swing.text.html.HTML$Tag tag, javax.swing.text.AttributeSet htmlAttrSet)
Maps HTML.Attribute.ALIGN to either: CSS.Attribute.TEXT_ALIGN CSS.Attribute.FLOAT CSS.Attribute.VERTICAL_ALIGN based on the tag associated with the attribute and the value of the attribute.

param
AttributeSet containing HTML attributes.
return
CSS.Attribute mapping for HTML.Attribute.ALIGN.

	return CSS.Attribute.TEXT_ALIGN;
/*
	String htmlAttrValue = (String)htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
	CSS.Attribute cssAttr = CSS.Attribute.TEXT_ALIGN;
	if (htmlAttrValue != null && htmlAttrSet instanceof Element) {
	    Element elem = (Element)htmlAttrSet;
	    if (!elem.isLeaf() && tag.isBlock() && validTextAlignValue(htmlAttrValue)) {
		return CSS.Attribute.TEXT_ALIGN;
	    } else if (isFloater(htmlAttrValue)) {
		return CSS.Attribute.FLOAT;
	    } else if (elem.isLeaf()) {
		return CSS.Attribute.VERTICAL_ALIGN;
	    }
 	}
	return null;
	*/
    
private javax.swing.text.html.CSS$Attribute[]getCssAttribute(javax.swing.text.html.HTML$Attribute hAttr)
Maps an HTML.Attribute object to its appropriate CSS.Attributes.

param
HTML.Attribute
return
CSS.Attribute[]

	return (CSS.Attribute[])htmlAttrToCssAttrMap.get(hAttr);
    
java.lang.ObjectgetCssValue(javax.swing.text.html.CSS$Attribute cssAttr, java.lang.String htmlAttrValue)
Given a CSS.Attribute object and its corresponding HTML.Attribute's value, this method returns a CssValue object to associate with the CSS attribute.

param
the CSS.Attribute
param
a String containing the value associated HTML.Attribtue.

	CssValue value = (CssValue)valueConvertor.get(cssAttr);
	Object o = value.parseHtmlValue(htmlAttrValue);
	return o;
    
java.awt.FontgetFont(javax.swing.text.StyleContext sc, javax.swing.text.AttributeSet a, int defaultSize, javax.swing.text.html.StyleSheet ss)
Returns the font for the values in the passed in AttributeSet. It is assumed the keys will be CSS.Attribute keys. sc is the StyleContext that will be messaged to get the font once the size, name and style have been determined.

        ss = getStyleSheet(ss);
	int size = getFontSize(a, defaultSize, ss);

	/*
	 * If the vertical alignment is set to either superscirpt or
	 * subscript we reduce the font size by 2 points.
	 */
	StringValue vAlignV = (StringValue)a.getAttribute
	                      (CSS.Attribute.VERTICAL_ALIGN);
	if ((vAlignV != null)) {
	    String vAlign = vAlignV.toString();
	    if ((vAlign.indexOf("sup") >= 0) ||
		(vAlign.indexOf("sub") >= 0)) {
		size -= 2;
	    }
	}
	
	FontFamily familyValue = (FontFamily)a.getAttribute
	                                    (CSS.Attribute.FONT_FAMILY);
	String family = (familyValue != null) ? familyValue.getValue() :
	                          "SansSerif";
	int style = Font.PLAIN;
	FontWeight weightValue = (FontWeight) a.getAttribute
	                          (CSS.Attribute.FONT_WEIGHT);
	if ((weightValue != null) && (weightValue.getValue() > 400)) {
	    style |= Font.BOLD;
	}
	Object fs = a.getAttribute(CSS.Attribute.FONT_STYLE);
	if ((fs != null) && (fs.toString().indexOf("italic") >= 0)) {
	    style |= Font.ITALIC;
	}
	Font f = sc.getFont(family, style, size);
	return f;
    
static intgetFontSize(javax.swing.text.AttributeSet attr, int defaultSize, javax.swing.text.html.StyleSheet ss)

	// PENDING(prinz) this is a 1.1 based implementation, need to also
	// have a 1.2 version.
	FontSize sizeValue = (FontSize)attr.getAttribute(CSS.Attribute.
							 FONT_SIZE);

	return (sizeValue != null) ? (int)sizeValue.getValue(attr, ss) :
	                             defaultSize;
    
private javax.swing.text.html.HTML$TaggetHTMLTag(javax.swing.text.AttributeSet htmlAttrSet)
Fetches the tag associated with the HTML AttributeSet.

param
AttributeSet containing the HTML attributes.
return
HTML.Tag

	Object o = htmlAttrSet.getAttribute(StyleConstants.NameAttribute);
	if (o instanceof HTML.Tag) {
	    HTML.Tag tag = (HTML.Tag) o;
	    return tag;
	}
	return null;
    
static intgetIndexOfSize(float pt, int[] sizeMap)

        for (int i = 0; i < sizeMap.length; i ++ )
                if (pt <= sizeMap[i])
                        return i + 1;
        return sizeMap.length;
    
static intgetIndexOfSize(float pt, javax.swing.text.html.StyleSheet ss)

        int[] sizeMap = (ss != null) ? ss.getSizeMap() : 
            StyleSheet.sizeMapDefault;
        return getIndexOfSize(pt, sizeMap);
    
java.lang.ObjectgetInternalCSSValue(javax.swing.text.html.CSS$Attribute key, java.lang.String value)
Gets the internal CSS representation of value which is a CSS value of the CSS attribute named key. The receiver should not modify value, and the first count strings are valid.

	CssValue conv = (CssValue) valueConvertor.get(key);
        Object r = conv.parseCssValue(value);
        return r != null ? r : conv.parseCssValue(key.getDefaultValue());
    
floatgetLength(javax.swing.text.AttributeSet a, javax.swing.text.html.CSS$Attribute key, javax.swing.text.html.StyleSheet ss)
Returns the length of the attribute in a with key key.

        ss = getStyleSheet(ss);
	LengthValue lv = (LengthValue) a.getAttribute(key);
        boolean isW3CLengthUnits = (ss == null) ? false : ss.isW3CLengthUnits();
        float len = (lv != null) ? lv.getValue(isW3CLengthUnits) : 0;
	return len;
    
floatgetPointSize(java.lang.String size, javax.swing.text.html.StyleSheet ss)
Returns the size of a font from the passed in string.

param
size CSS string describing font size
param
baseFontSize size to use for relative units.

	int relSize, absSize, diff, index;
        ss = getStyleSheet(ss);
	if (size != null) {
	    if (size.startsWith("+")) {
		relSize = Integer.valueOf(size.substring(1)).intValue();
		return getPointSize(baseFontSize + relSize, ss);
	    } else if (size.startsWith("-")) {
		relSize = -Integer.valueOf(size.substring(1)).intValue();
		return getPointSize(baseFontSize + relSize, ss);
	    } else {
		absSize = Integer.valueOf(size).intValue();
		return getPointSize(absSize, ss);
	    }
	}
	return 0;
    
floatgetPointSize(int index, javax.swing.text.html.StyleSheet ss)
Return the point size, given a size index. Legal HTML index sizes are 1-7.

        ss = getStyleSheet(ss);
        int[] sizeMap = (ss != null) ? ss.getSizeMap() : 
            StyleSheet.sizeMapDefault;
        --index;
	if (index < 0)
	  return sizeMap[0];
	else if (index > sizeMap.length - 1)
	  return sizeMap[sizeMap.length - 1];
	else
	  return sizeMap[index];
    
private javax.swing.text.html.StyleSheetgetStyleSheet(javax.swing.text.html.StyleSheet ss)

        if (ss != null) {
            styleSheet = ss;
        }
        return styleSheet;
    
static java.net.URLgetURL(java.net.URL base, java.lang.String cssString)
Returns a URL for the given CSS url string. If relative, base is used as the parent. If a valid URL can not be found, this will not throw a MalformedURLException, instead null will be returned.

	if (cssString == null) {
	    return null;
	}
	if (cssString.startsWith("url(") &&
	    cssString.endsWith(")")) {
	    cssString = cssString.substring(4, cssString.length() - 1);
	}
	// Absolute first
	try {
	    URL url = new URL(cssString);
	    if (url != null) {
		return url;
	    }
	} catch (MalformedURLException mue) {
	}
	// Then relative
	if (base != null) {
	    // Relative URL, try from base
	    try {
		URL url = new URL(base, cssString);
		return url;
	    }
	    catch (MalformedURLException muee) {
	    }
	}
	return null;
    
static final javax.swing.text.html.CSS$ValuegetValue(java.lang.String name)
Translates a string to a CSS.Value object. This will return null if there is no value by the given name.

param
name the name of the CSS value to fetch the typesafe enumeration for
return
the CSS.Value object, or null if the string doesn't represent a valid CSS value name; this does not mean that it doesn't represent a valid CSS value

	return (Value) valueMap.get(name);
    
static final java.awt.ColorhexToColor(java.lang.String value)
Convert a "#FFFFFF" hex string to a Color. If the color specification is bad, an attempt will be made to fix it up.

	String digits;
	int n = value.length();
	if (value.startsWith("#")) {
	    digits = value.substring(1, Math.min(value.length(), 7));
	} else {
	    digits = value;
	}
	String hstr = "0x" + digits;
	Color c;
	try {
	    c = Color.decode(hstr);
	} catch (NumberFormatException nfe) {
	    c = null;
	}
	 return c;
     
private booleanisFloater(java.lang.String alignValue)

	return (alignValue.equals("left") || alignValue.equals("right"));
    
private booleanisHTMLFontTag(javax.swing.text.html.HTML$Tag tag)

	return (tag != null && ((tag == HTML.Tag.FONT) || (tag == HTML.Tag.BASEFONT)));
    
private static java.awt.ColorparseRGB(java.lang.String string)
Parses a String in the format rgb(r, g, b) where each of the Color components is either an integer, or a floating number with a % after indicating a percentage value of 255. Values are constrained to fit with 0-255. The resulting Color is returned.

        // Find the next numeric char
        int[] index = new int[1];

        index[0] = 4;
        int red = getColorComponent(string, index);
        int green = getColorComponent(string, index);
        int blue = getColorComponent(string, index);

        return new Color(red, green, blue);
    
static java.lang.String[]parseStrings(java.lang.String value)

return
an array of all the strings in value that are separated by whitespace.

	int         current, last;
	int         length = (value == null) ? 0 : value.length();
	Vector      temp = new Vector(4);

	current = 0;
	while (current < length) {
	    // Skip ws
	    while (current < length && Character.isWhitespace
		   (value.charAt(current))) {
		current++;
	    }
	    last = current;
	    while (current < length && !Character.isWhitespace
		   (value.charAt(current))) {
		current++;
	    }
	    if (last != current) {
		temp.addElement(value.substring(last, current));
	    }
	    current++;
	}
	String[] retValue = new String[temp.size()];
	temp.copyInto(retValue);
	return retValue;
    
private voidreadObject(java.io.ObjectInputStream s)

        s.defaultReadObject();
	// Reconstruct the hashtable.
	int numValues = s.readInt();
	valueConvertor = new Hashtable(Math.max(1, numValues));
	while (numValues-- > 0) {
	    Object key = s.readObject();
	    Object value = s.readObject();
	    Object staticKey = StyleContext.getStaticAttribute(key);
	    if (staticKey != null) {
		key = staticKey;
	    }
	    Object staticValue = StyleContext.getStaticAttribute(value);
	    if (staticValue != null) {
		value = staticValue;
	    }
	    if (key != null && value != null) {
		valueConvertor.put(key, value);
	    }
	}
    
voidsetBaseFontSize(int sz)
Sets the base font size. sz is a CSS value, and is not necessarily the point size. Use getPointSize to determine the point size corresponding to sz.

	if (sz < 1)
	  baseFontSize = 0;
	else if (sz > 7)
	  baseFontSize = 7;
	else
	  baseFontSize = sz;
    
voidsetBaseFontSize(java.lang.String size)
Sets the base font size from the passed in string.

	int relSize, absSize, diff;

	if (size != null) {
	    if (size.startsWith("+")) {
		relSize = Integer.valueOf(size.substring(1)).intValue();
		setBaseFontSize(baseFontSize + relSize);
	    } else if (size.startsWith("-")) {
		relSize = -Integer.valueOf(size.substring(1)).intValue();
		setBaseFontSize(baseFontSize + relSize);
	    } else {
		setBaseFontSize(Integer.valueOf(size).intValue());
	    }
	}
    
static java.awt.ColorstringToColor(java.lang.String str)
Convert a color string such as "RED" or "#NNNNNN" or "rgb(r, g, b)" to a Color.

      Color color = null;

      if (str.length() == 0)
        color = Color.black;
      else if (str.startsWith("rgb(")) {
          color = parseRGB(str);
      }
      else if (str.charAt(0) == '#")
        color = hexToColor(str);
      else if (str.equalsIgnoreCase("Black"))
        color = hexToColor("#000000");
      else if(str.equalsIgnoreCase("Silver"))
        color = hexToColor("#C0C0C0");
      else if(str.equalsIgnoreCase("Gray"))
        color = hexToColor("#808080");
      else if(str.equalsIgnoreCase("White"))
        color = hexToColor("#FFFFFF");
      else if(str.equalsIgnoreCase("Maroon"))
        color = hexToColor("#800000");
      else if(str.equalsIgnoreCase("Red"))
        color = hexToColor("#FF0000");
      else if(str.equalsIgnoreCase("Purple"))
        color = hexToColor("#800080");
      else if(str.equalsIgnoreCase("Fuchsia"))
        color = hexToColor("#FF00FF");
      else if(str.equalsIgnoreCase("Green"))
        color = hexToColor("#008000");
      else if(str.equalsIgnoreCase("Lime"))
        color = hexToColor("#00FF00");
      else if(str.equalsIgnoreCase("Olive"))
        color = hexToColor("#808000");
      else if(str.equalsIgnoreCase("Yellow"))
        color = hexToColor("#FFFF00");
      else if(str.equalsIgnoreCase("Navy"))
        color = hexToColor("#000080");
      else if(str.equalsIgnoreCase("Blue"))
        color = hexToColor("#0000FF");
      else if(str.equalsIgnoreCase("Teal"))
        color = hexToColor("#008080");
      else if(str.equalsIgnoreCase("Aqua"))
        color = hexToColor("#00FFFF");
      else
	  color = hexToColor(str); // sometimes get specified without leading #
      return color;
    
javax.swing.text.html.CSS$AttributestyleConstantsKeyToCSSKey(javax.swing.text.StyleConstants sc)
Maps from a StyleConstants to a CSS Attribute.

	return (Attribute)styleConstantToCssMap.get(sc);
    
java.lang.ObjectstyleConstantsValueToCSSValue(javax.swing.text.StyleConstants sc, java.lang.Object styleValue)
Maps from a StyleConstants value to a CSS value.

	Object cssKey = styleConstantsKeyToCSSKey(sc);
	if (cssKey != null) {
	    CssValue conv = (CssValue)valueConvertor.get(cssKey);
	    return conv.fromStyleConstants(sc, styleValue);
	}
	return null;
    
private voidtranslateAttribute(javax.swing.text.html.HTML$Attribute key, javax.swing.text.AttributeSet htmlAttrSet, javax.swing.text.MutableAttributeSet cssAttrSet)

	/*
	 * In the case of all remaining HTML.Attribute's they
	 * map to 1 or more CCS.Attribute.
	 */
	CSS.Attribute[] cssAttrList = getCssAttribute(key);
	
	String htmlAttrValue = (String)htmlAttrSet.getAttribute(key);
	
	if (cssAttrList == null || htmlAttrValue == null) {
	    return;
	}
	for (int i = 0; i < cssAttrList.length; i++) {
	    Object o = getCssValue(cssAttrList[i], htmlAttrValue);
	    if (o != null) {
		cssAttrSet.addAttribute(cssAttrList[i], o);
	    }
	}
    
private voidtranslateAttributes(javax.swing.text.html.HTML$Tag tag, javax.swing.text.AttributeSet htmlAttrSet, javax.swing.text.MutableAttributeSet cssAttrSet)

	Enumeration names = htmlAttrSet.getAttributeNames();
	while (names.hasMoreElements()) {
	    Object name = names.nextElement();

	    if (name instanceof HTML.Attribute) {
		HTML.Attribute key = (HTML.Attribute)name;

		/*
		 * HTML.Attribute.ALIGN needs special processing.
		 * It can map to to 1 of many(3) possible CSS attributes
		 * depending on the nature of the tag the attribute is
		 * part off and depending on the value of the attribute.
		 */
		if (key == HTML.Attribute.ALIGN) {
		    String htmlAttrValue = (String)htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
		    if (htmlAttrValue != null) {
			CSS.Attribute cssAttr = getCssAlignAttribute(tag, htmlAttrSet);
			if (cssAttr != null) {
			    Object o = getCssValue(cssAttr, htmlAttrValue);
			    if (o != null) {
				cssAttrSet.addAttribute(cssAttr, o);
			    }
			}
		    }
		} else {

		    /*
		     * The html size attribute has a mapping in the CSS world only
		     * if it is par of a font or base font tag.
		     */

		    if (key == HTML.Attribute.SIZE && !isHTMLFontTag(tag)) {
			continue;
		    }

		    translateAttribute(key, htmlAttrSet, cssAttrSet);
		}
	    } else if (name instanceof CSS.Attribute) {
		cssAttrSet.addAttribute(name, htmlAttrSet.getAttribute(name));
	    }
	}
    
private voidtranslateEmbeddedAttributes(javax.swing.text.AttributeSet htmlAttrSet, javax.swing.text.MutableAttributeSet cssAttrSet)

	Enumeration keys = htmlAttrSet.getAttributeNames();
	if (htmlAttrSet.getAttribute(StyleConstants.NameAttribute) ==
	    HTML.Tag.HR) {
	    // HR needs special handling due to us treating it as a leaf.
	    translateAttributes(HTML.Tag.HR, htmlAttrSet, cssAttrSet);
	}
	while (keys.hasMoreElements()) {
	    Object key = keys.nextElement();
	    if (key instanceof HTML.Tag) {
		HTML.Tag tag = (HTML.Tag)key;
		Object o = htmlAttrSet.getAttribute(tag);
		if (o != null && o instanceof AttributeSet) {
		    translateAttributes(tag, (AttributeSet)o, cssAttrSet);
		}
	    } else if (key instanceof CSS.Attribute) {
		cssAttrSet.addAttribute(key, htmlAttrSet.getAttribute(key));
	    }
	}
    
javax.swing.text.AttributeSettranslateHTMLToCSS(javax.swing.text.AttributeSet htmlAttrSet)
Convert a set of HTML attributes to an equivalent set of CSS attributes.

param
AttributeSet containing the HTML attributes.
return
AttributeSet containing the corresponding CSS attributes. The AttributeSet will be empty if there are no mapping CSS attributes.

	MutableAttributeSet cssAttrSet = new SimpleAttributeSet();
	Element elem = (Element)htmlAttrSet;
	HTML.Tag tag = getHTMLTag(htmlAttrSet);
	if ((tag == HTML.Tag.TD) || (tag == HTML.Tag.TH)) {
	    // translate border width into the cells
	    AttributeSet tableAttr = elem.getParentElement().
		                     getParentElement().getAttributes();
	    translateAttribute(HTML.Attribute.BORDER, tableAttr, cssAttrSet);
	    String pad = (String)tableAttr.getAttribute(HTML.Attribute.CELLPADDING);
	    if (pad != null) {
		LengthValue v = 
		    (LengthValue)getInternalCSSValue(CSS.Attribute.PADDING_TOP, pad);
		v.span = (v.span < 0) ? 0 : v.span;
		cssAttrSet.addAttribute(CSS.Attribute.PADDING_TOP, v);
		cssAttrSet.addAttribute(CSS.Attribute.PADDING_BOTTOM, v);
		cssAttrSet.addAttribute(CSS.Attribute.PADDING_LEFT, v);
		cssAttrSet.addAttribute(CSS.Attribute.PADDING_RIGHT, v);
	    }
	}
	if (elem.isLeaf()) {
	    translateEmbeddedAttributes(htmlAttrSet, cssAttrSet);
	} else {
	    translateAttributes(tag, htmlAttrSet, cssAttrSet);
	}
	if (tag == HTML.Tag.CAPTION) {
	    /* 
	     * Navigator uses ALIGN for caption placement and IE uses VALIGN.
	     */
	    Object v = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
	    if ((v != null) && (v.equals("top") || v.equals("bottom"))) {
		cssAttrSet.addAttribute(CSS.Attribute.CAPTION_SIDE, v);
		cssAttrSet.removeAttribute(CSS.Attribute.TEXT_ALIGN);
	    } else {
		v = htmlAttrSet.getAttribute(HTML.Attribute.VALIGN);
		if (v != null) {
		    cssAttrSet.addAttribute(CSS.Attribute.CAPTION_SIDE, v);
		}
	    }
	}
	return cssAttrSet;
    
private booleanvalidTextAlignValue(java.lang.String alignValue)

	return (isFloater(alignValue) || alignValue.equals("center"));
    
private voidwriteObject(java.io.ObjectOutputStream s)

    

    //
    // Serialization support
    //

       
         
    
        s.defaultWriteObject();

	// Determine what values in valueConvertor need to be written out.
	Enumeration keys = valueConvertor.keys();
	s.writeInt(valueConvertor.size());
	if (keys != null) {
	    while (keys.hasMoreElements()) {
		Object key = keys.nextElement();
		Object value = valueConvertor.get(key);
		if (!(key instanceof Serializable) &&
		    (key = StyleContext.getStaticAttributeKey(key)) == null) {
		    // Should we throw an exception here?
		    key = null;
		    value = null;
		}
		else if (!(value instanceof Serializable) &&
		    (value = StyleContext.getStaticAttributeKey(value)) == null){
		    // Should we throw an exception here?
		    key = null;
		    value = null;
		}
		s.writeObject(key);
		s.writeObject(value);
	    }
	}