BATIK-1092: Add text background support (preliminary).

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/batik/branches/text-background-integration@1816962 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/batik-bridge/src/main/java/org/apache/batik/bridge/PaintServer.java b/batik-bridge/src/main/java/org/apache/batik/bridge/PaintServer.java
index 4caa51a..53014a5 100644
--- a/batik-bridge/src/main/java/org/apache/batik/bridge/PaintServer.java
+++ b/batik-bridge/src/main/java/org/apache/batik/bridge/PaintServer.java
@@ -27,6 +27,8 @@
 import java.io.IOException;
 
 import org.apache.batik.css.engine.SVGCSSEngine;
+import org.apache.batik.css.engine.value.ComputedValue;
+import org.apache.batik.css.engine.value.RGBAColorValue;
 import org.apache.batik.css.engine.value.Value;
 import org.apache.batik.css.engine.value.svg.ICCColor;
 import org.apache.batik.css.engine.value.svg12.CIELabColor;
@@ -247,6 +249,28 @@
     }
 
     /**
+     * Converts for the specified element, its background paint properties
+     * to a Paint object.
+     *
+     * @param backgroundElement the element interested in a Paint
+     * @param backgroundNode the graphics node to fill
+     * @param ctx the bridge context
+     */
+    public static Paint convertBackgroundPaint(Element backgroundElement,
+                                         GraphicsNode backgroundNode,
+                                         BridgeContext ctx) {
+        Value v = CSSUtilities.getComputedStyle
+            (backgroundElement, SVGCSSEngine.BACKGROUND_COLOR_INDEX);
+        float opacity = 1f;
+
+        return convertPaint(backgroundElement,
+                            backgroundNode,
+                            v,
+                            opacity,
+                            ctx);
+    }
+
+    /**
      * Converts a Paint definition to a concrete <code>java.awt.Paint</code>
      * instance according to the specified parameters.
      *
@@ -584,9 +608,15 @@
      * @param opacity The opacity value (0 &lt;= o &lt;= 1).
      */
     public static Color convertColor(Value c, float opacity) {
+        if (c instanceof ComputedValue)
+            c = ((ComputedValue)c).getComputedValue();
         int r = resolveColorComponent(c.getRed());
         int g = resolveColorComponent(c.getGreen());
         int b = resolveColorComponent(c.getBlue());
+        if (c instanceof RGBAColorValue) {
+            return new Color(r, g, b,
+                Math.round(resolveAlphaComponent(((RGBAColorValue)c).getAlpha()) * 255f));
+        } else
         return new Color(r, g, b, Math.round(opacity * 255f));
     }
 
@@ -758,6 +788,27 @@
     }
 
     /**
+     * Returns the value of the alpha component as a float in range [0.0, 1.0].
+     * @param v the value that defines the alpha component
+     */
+    public static float resolveAlphaComponent(Value v) {
+        float f;
+        switch(v.getPrimitiveType()) {
+        case CSSPrimitiveValue.CSS_PERCENTAGE:
+            f = v.getFloatValue();
+            f = (f > 100f) ? 100f : (f < 0f) ? 0f : f;
+            return f / 100f;
+        case CSSPrimitiveValue.CSS_NUMBER:
+            f = v.getFloatValue();
+            f = (f > 1f) ? 1f : (f < 0f) ? 0f : f;
+            return f;
+        default:
+            throw new IllegalArgumentException
+                ("Alpha component argument is not an appropriate CSS value");
+        }
+    }
+
+    /**
      * Returns the opacity represented by the specified CSSValue.
      * @param v the value that represents the opacity
      * @return the opacity between 0 and 1
diff --git a/batik-bridge/src/main/java/org/apache/batik/bridge/SVGTextElementBridge.java b/batik-bridge/src/main/java/org/apache/batik/bridge/SVGTextElementBridge.java
index 5a9dfec..dff1eed 100644
--- a/batik-bridge/src/main/java/org/apache/batik/bridge/SVGTextElementBridge.java
+++ b/batik-bridge/src/main/java/org/apache/batik/bridge/SVGTextElementBridge.java
@@ -20,6 +20,7 @@
 
 import java.awt.AlphaComposite;
 import java.awt.Color;
+import java.awt.Paint;
 import java.awt.RenderingHints;
 import java.awt.Shape;
 import java.awt.font.TextAttribute;
@@ -70,6 +71,7 @@
 import org.apache.batik.gvt.text.TextPath;
 import org.apache.batik.util.XMLConstants;
 
+
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.css.CSSPrimitiveValue;
@@ -82,6 +84,9 @@
 import org.w3c.dom.svg.SVGTextContentElement;
 import org.w3c.dom.svg.SVGTextPositioningElement;
 
+
+import org.apache.batik.css.engine.value.StringValue;
+
 /**
  * Bridge class for the &lt;text&gt; element.
  *
@@ -94,6 +99,8 @@
 
     protected static final Integer ZERO = 0;
 
+    public static final Color TRANSPARENT = new Color(0, 0, 0, 0);
+
     public static final
         AttributedCharacterIterator.Attribute TEXT_COMPOUND_DELIMITER =
         GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER;
@@ -129,6 +136,14 @@
         AttributedCharacterIterator.Attribute BASELINE_SHIFT
         = GVTAttributedCharacterIterator.TextAttribute.BASELINE_SHIFT;
 
+    public static final
+        AttributedCharacterIterator.Attribute LINE_HEIGHT
+        = GVTAttributedCharacterIterator.TextAttribute.LINE_HEIGHT;
+
+    public static final
+        AttributedCharacterIterator.Attribute BACKGROUND_OUTLINE
+        = GVTAttributedCharacterIterator.TextAttribute.BACKGROUND_OUTLINE;
+
     protected AttributedString laidoutText;
 
     // This is used to track the TextPainterInfo for each element
@@ -627,11 +642,13 @@
         TextNode tn = (TextNode)node;
         elemTPI.clear();
 
-        AttributedString as = buildAttributedString(ctx, e);
+        Map[] returnTextAttributes = new Map[1];
+        AttributedString as = buildAttributedString(ctx, e, returnTextAttributes);
         if (as == null) {
             tn.setAttributedCharacterIterator(null);
             return;
         }
+        Map textAttributes = returnTextAttributes[0];
 
         addGlyphPositionAttributes(as, e, ctx);
         if (ctx.isDynamic()) {
@@ -639,7 +656,7 @@
         }
 
         // Install the ACI in the text node.
-        tn.setAttributedCharacterIterator(as.getIterator());
+        tn.setAttributedCharacterIterator(as.getIterator(), textAttributes);
 
         // Now get the real paint into - this needs to
         // wait until the text node is laidout so we can get
@@ -653,7 +670,7 @@
 
         if (usingComplexSVGFont) {
             // Force Complex SVG fonts to be recreated, if we have them.
-            tn.setAttributedCharacterIterator(as.getIterator());
+            tn.setAttributedCharacterIterator(as.getIterator(), textAttributes);
         }
 
         if (ctx.isDynamic()) {
@@ -747,6 +764,12 @@
      */
     protected void handleCSSPropertyChanged(int property) {
         switch(property) {                  // fall-through is intended
+        case SVGCSSEngine.BACKGROUND_COLOR_INDEX:
+        case SVGCSSEngine.BACKGROUND_MODE_INDEX:
+        case SVGCSSEngine.BACKGROUND_OUTLINE_BOTTOM_INDEX:
+        case SVGCSSEngine.BACKGROUND_OUTLINE_LEFT_INDEX:
+        case SVGCSSEngine.BACKGROUND_OUTLINE_RIGHT_INDEX:
+        case SVGCSSEngine.BACKGROUND_OUTLINE_TOP_INDEX:
         case SVGCSSEngine.FILL_INDEX:
         case SVGCSSEngine.FILL_OPACITY_INDEX:
         case SVGCSSEngine.STROKE_INDEX:
@@ -816,7 +839,8 @@
         if (usingComplexSVGFont)
             // Force Complex SVG fonts to be recreated
             textNode.setAttributedCharacterIterator
-                (textNode.getAttributedCharacterIterator());
+                (textNode.getAttributedCharacterIterator(),
+                 textNode.getTextAttributes());
     }
 
     int getElementStartIndex(Element element) {
@@ -845,12 +869,15 @@
      */
     protected AttributedString buildAttributedString(BridgeContext ctx,
                                                      Element element) {
-
-        AttributedStringBuffer asb = new AttributedStringBuffer();
-        fillAttributedStringBuffer(ctx, element, true, null, null, null, asb);
-        return asb.toAttributedString();
+        return this.buildAttributedString(ctx, element, null);
     }
 
+    protected AttributedString buildAttributedString(BridgeContext ctx,
+                                                     Element element, Map[] returnTextAttributes) {
+        AttributedStringBuffer asb = new AttributedStringBuffer();
+        fillAttributedStringBuffer(ctx, element, true, null, null, null, asb, returnTextAttributes);
+        return asb.toAttributedString();
+    }
 
     /**
      * This is used to store the end of the last piece of text
@@ -870,6 +897,17 @@
                                               Integer bidiLevel,
                                               Map initialAttributes,
                                               AttributedStringBuffer asb) {
+        this.fillAttributedStringBuffer(ctx, element, top, textPath, bidiLevel, initialAttributes, asb);
+    }
+
+    protected void fillAttributedStringBuffer(BridgeContext ctx,
+                                              Element element,
+                                              boolean top,
+                                              TextPath textPath,
+                                              Integer bidiLevel,
+                                              Map initialAttributes,
+                                              AttributedStringBuffer asb,
+                                              Map[] returnTextAttributes) {
         // 'requiredFeatures', 'requiredExtensions', 'systemLanguage' &
         // 'display="none".
         if ((!SVGUtilities.matchUserAgent(element, ctx.getUserAgent())) ||
@@ -893,8 +931,13 @@
         Map map = initialAttributes == null
                 ? new HashMap()
                 : new HashMap(initialAttributes);
+        // augment initial attributes with this element's attribute map
         initialAttributes =
             getAttributeMap(ctx, element, textPath, bidiLevel, map);
+        // retain top level text element's attributes
+        if (returnTextAttributes != null)
+            returnTextAttributes[0] = map;
+        // batik bidi processing
         Object o = map.get(TextAttribute.BIDI_EMBEDDING);
         Integer subBidiLevel = bidiLevel;
         if (o != null) {
@@ -933,7 +976,7 @@
                                                textPath,
                                                subBidiLevel,
                                                initialAttributes,
-                                               asb);
+                                               asb, null);
                     if (asb.count != before) {
                         initialAttributes = null;
                     }
@@ -950,7 +993,7 @@
                                                    newTextPath,
                                                    subBidiLevel,
                                                    initialAttributes,
-                                                   asb);
+                                                   asb, null);
                         if (asb.count != before) {
                             initialAttributes = null;
                         }
@@ -997,7 +1040,7 @@
                                                textPath,
                                                subBidiLevel,
                                                initialAttributes,
-                                               asb);
+                                               asb, null);
                     if (asb.count != before) {
                         initialAttributes = null;
                     }
@@ -1532,6 +1575,11 @@
         // holds hard ref to DOM.
         result.put(GVT_FONT_FAMILIES, fontFamilyList);
 
+        // Line height
+        result.put(LINE_HEIGHT,
+                   TextUtilities.convertLineHeight(element,
+                   SVGCSSEngine.LINE_HEIGHT_INDEX, fontSize));
+
         if (!ctx.isDynamic()) {
             // Only leave this in the map for dynamic documents.
             // Otherwise it will cause the whole DOM to stay when
@@ -1585,6 +1633,11 @@
         result.put(PAINT_INFO, pi);
         elemTPI.put(element, pi);
 
+        // Background outline
+        float[] backgroundOutline = TextUtilities.convertBackgroundOutline(element);
+        result.put(BACKGROUND_OUTLINE, backgroundOutline);
+
+        // Text path
         if (textPath != null) {
             result.put(TEXTPATH, textPath);
         }
@@ -1885,7 +1938,9 @@
             (sm.isNullCascaded(SVGCSSEngine.FILL_INDEX)) &&
             (sm.isNullCascaded(SVGCSSEngine.STROKE_INDEX)) &&
             (sm.isNullCascaded(SVGCSSEngine.STROKE_WIDTH_INDEX)) &&
-            (sm.isNullCascaded(SVGCSSEngine.OPACITY_INDEX))) {
+            (sm.isNullCascaded(SVGCSSEngine.OPACITY_INDEX)) &&
+            (sm.isNullCascaded(SVGCSSEngine.BACKGROUND_COLOR_INDEX)) &&
+            (sm.isNullCascaded(SVGCSSEngine.BACKGROUND_MODE_INDEX))) {
             // If not, keep the same decorations.
             return pi;
         }
@@ -1906,6 +1961,13 @@
             pi.composite    = AlphaComposite.SrcOver;
 
         pi.visible      = CSSUtilities.convertVisibility(element);
+        StyleMap sm = ((CSSStylableElement)element).getComputedStyleMap(null);
+        Paint backgroundPaint = PaintServer.convertBackgroundPaint(element, node, ctx);
+        if (!sm.isNullCascaded(SVGCSSEngine.BACKGROUND_COLOR_INDEX))
+            pi.backgroundPaint = backgroundPaint;
+        StringValue backgroundMode = TextUtilities.convertBackgroundMode(element);
+        if (!sm.isNullCascaded(SVGCSSEngine.BACKGROUND_MODE_INDEX))
+            pi.backgroundMode = backgroundMode.getStringValue();
         pi.fillPaint    = PaintServer.convertFillPaint  (element, node, ctx);
         pi.strokePaint  = PaintServer.convertStrokePaint(element, node, ctx);
         pi.strokeStroke = PaintServer.convertStroke     (element);
diff --git a/batik-bridge/src/main/java/org/apache/batik/bridge/StrokingTextPainter.java b/batik-bridge/src/main/java/org/apache/batik/bridge/StrokingTextPainter.java
index 0979e8c..03224b7 100644
--- a/batik-bridge/src/main/java/org/apache/batik/bridge/StrokingTextPainter.java
+++ b/batik-bridge/src/main/java/org/apache/batik/bridge/StrokingTextPainter.java
@@ -16,9 +16,9 @@
    limitations under the License.
 
  */
-
 package org.apache.batik.bridge;
 
+import java.awt.Color;
 import java.awt.Graphics2D;
 import java.awt.Paint;
 import java.awt.RenderingHints;
@@ -29,6 +29,7 @@
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
+import java.lang.ref.SoftReference;
 import java.text.AttributedCharacterIterator;
 import java.text.AttributedString;
 import java.text.CharacterIterator;
@@ -36,11 +37,13 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.batik.gvt.font.GVTFont;
 import org.apache.batik.gvt.font.GVTFontFamily;
 import org.apache.batik.gvt.font.GVTGlyphMetrics;
+import org.apache.batik.gvt.font.GVTGlyphVector;
 import org.apache.batik.gvt.font.GVTLineMetrics;
 import org.apache.batik.gvt.text.AttributedCharacterSpanIterator;
 import org.apache.batik.gvt.text.BidiAttributedCharacterIterator;
@@ -48,7 +51,6 @@
 import org.apache.batik.gvt.text.TextPaintInfo;
 import org.apache.batik.gvt.text.TextPath;
 
-
 /**
  * More sophisticated implementation of TextPainter which
  * renders the attributed character iterator of a <code>TextNode</code>.
@@ -124,13 +126,20 @@
     public static final GVTAttributedCharacterIterator.TextAttribute ALT_GLYPH_HANDLER =
         GVTAttributedCharacterIterator.TextAttribute.ALT_GLYPH_HANDLER;
 
+    public static final
+        AttributedCharacterIterator.Attribute LINE_HEIGHT
+        = GVTAttributedCharacterIterator.TextAttribute.LINE_HEIGHT;
+
+    public static final
+        AttributedCharacterIterator.Attribute BACKGROUND_OUTLINE
+        = GVTAttributedCharacterIterator.TextAttribute.BACKGROUND_OUTLINE;
+
     static Set extendedAtts = new HashSet();
 
     static {
         extendedAtts.add(FLOW_PARAGRAPH);
         extendedAtts.add(TEXT_COMPOUND_ID);
         extendedAtts.add(GVT_FONT);
-        // extendedAtts.add(BIDI_LEVEL);
     }
 
     /**
@@ -159,13 +168,17 @@
 
         List textRuns = getTextRuns(node, aci);
 
-        // draw the underline and overline first, then the actual text
-        // and finally the strikethrough
+        // 1. draw text node background
+        paintBackground(node, textRuns, g2d);
+        // 2. draw text run backgrounds
+        paintBackgrounds(node, textRuns, g2d);
+        // 3. draw text run underline and overline
         paintDecorations(textRuns, g2d, TextSpanLayout.DECORATION_UNDERLINE);
         paintDecorations(textRuns, g2d, TextSpanLayout.DECORATION_OVERLINE);
+        // 4. draw text run glyphs
         paintTextRuns(textRuns, g2d);
-        paintDecorations
-            (textRuns, g2d, TextSpanLayout.DECORATION_STRIKETHROUGH);
+        // 5. draw text run strike through
+        paintDecorations(textRuns, g2d, TextSpanLayout.DECORATION_STRIKETHROUGH);
     }
 
     protected void printAttrs(AttributedCharacterIterator aci) {
@@ -851,6 +864,158 @@
     }
 
     /**
+     * Paint text node background.
+     */
+    protected void paintBackground(TextNode node, List textRuns, Graphics2D g2d) {
+        Map textAttributes = node.getTextAttributes();
+        if (textAttributes != null) {
+            TextPaintInfo tpi = (TextPaintInfo) textAttributes.get(PAINT_INFO);
+            if (tpi != null) {
+                if (tpi.visible) {
+                    Paint paint = tpi.backgroundPaint;
+                    String mode = tpi.backgroundMode;
+                    if (paint != null) {
+                        if ((paint instanceof Color) && (((Color)paint).getAlpha() != 0)) {
+                            Rectangle2D bounds = computeBackgroundBounds(node, textRuns, mode);
+                            if (!bounds.isEmpty()) {
+                                g2d.setPaint(paint);
+                                adjustForOutline(bounds, (float[]) textAttributes.get(BACKGROUND_OUTLINE));
+                                g2d.fill(bounds);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private Rectangle2D computeBackgroundBounds(TextNode node, List textRuns, String mode) {
+        if (mode == TextPaintInfo.BBOX) {
+            return computeBBoxBounds(node.getPrimitiveBounds());
+        } else if (mode == TextPaintInfo.LINE_HEIGHT) {
+            TextRun run = (TextRun) textRuns.get(0);
+            TextSpanLayout layout = run.getLayout();
+            GVTLineMetrics lineMetrics = layout.getLineMetrics();
+            double ascent = lineMetrics.getAscent();
+            double descent = lineMetrics.getDescent();
+            double emHeight = ascent + descent;
+            GVTGlyphVector gv = layout.getGlyphVector();
+            Point2D firstPosition = gv.getGlyphPosition(0);
+            Map textAttributes = node.getTextAttributes();
+            double fontSize = (textAttributes != null) ? ((Float) textAttributes.get(TextAttribute.SIZE)).doubleValue() : 0d;
+            double lineHeight = (textAttributes != null) ? ((Float) textAttributes.get(LINE_HEIGHT)).doubleValue() : fontSize * 1.1f;
+            return computeLineHeightBounds(firstPosition, ascent, emHeight, lineHeight, node.getPrimitiveBounds().getWidth());
+        } else {
+            return new Rectangle2D.Double();
+        }
+    }
+
+    /**
+     * Paint text run backgrounds.
+     */
+    protected void paintBackgrounds(TextNode node, List textRuns, Graphics2D g2d) {
+        Map textAttributes = node.getTextAttributes();
+        if (textAttributes != null) {
+            TextPaintInfo tpiText = (TextPaintInfo) textAttributes.get(PAINT_INFO);
+            if (tpiText != null) {
+                if (tpiText.visible) {
+                    int numRuns = textRuns.size();
+                    List elements = new java.util.ArrayList(numRuns);
+                    for (int i = 0; i < numRuns; i++) {
+                        TextRun textRun = (TextRun)textRuns.get(i);
+                        AttributedCharacterIterator runaci = textRun.getACI();
+                        runaci.first();
+                        elements.add(((SoftReference) runaci.getAttribute(TEXT_COMPOUND_ID)).get());
+                    }
+                    Set eDrawn = new HashSet();
+                    for (int i = 0; i < numRuns; i++) {
+                        TextRun textRun = (TextRun)textRuns.get(i);
+                        AttributedCharacterIterator runaci = textRun.getACI();
+                        runaci.first();
+                        TextPaintInfo tpi = (TextPaintInfo)runaci.getAttribute(PAINT_INFO);
+                        if (tpi != null) {
+                            Object e = elements.get(i);
+                            if ((tpi == tpiText) || eDrawn.contains(e))
+                                continue;
+                            else if (tpi.visible) {
+                                Paint paint = tpi.backgroundPaint;
+                                String mode = tpi.backgroundMode;
+                                if (paint != null) {
+                                    if ((paint instanceof Color) && (((Color)paint).getAlpha() != 0)) {
+                                        GeneralPath p = new GeneralPath();
+                                        for (int j = i; j < numRuns; j++) {
+                                            Object eRun = elements.get(j);
+                                            if (eRun == e) {
+                                                Rectangle2D bRun = computeBackgroundBounds((TextRun) textRuns.get(j), mode);
+                                                p.append(bRun, false);
+                                            }
+                                        }
+                                        Rectangle2D bounds = p.getBounds2D();
+                                        if (!bounds.isEmpty()) {
+                                            g2d.setPaint(paint);
+                                            adjustForOutline(bounds, (float[]) runaci.getAttribute(BACKGROUND_OUTLINE));
+                                            g2d.fill(bounds);
+                                        }
+                                    }
+                                }
+                                eDrawn.add(e);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private Rectangle2D computeBackgroundBounds(TextRun run, String mode) {
+        if (mode == TextPaintInfo.BBOX) {
+            return computeBBoxBounds(run.getLayout().getBounds2D());
+        } else if (mode == TextPaintInfo.LINE_HEIGHT) {
+            TextSpanLayout layout = run.getLayout();
+            GVTLineMetrics lineMetrics = layout.getLineMetrics();
+            double ascent = lineMetrics.getAscent();
+            double descent = lineMetrics.getDescent();
+            double emHeight = ascent + descent;
+            GVTGlyphVector gv = layout.getGlyphVector();
+            Rectangle2D bbox = layout.getBounds2D();
+            Point2D firstPosition = new Point2D.Double(bbox.getX(), gv.getGlyphPosition(0).getY());
+            AttributedCharacterIterator aci = run.getACI();
+            double fontSize = (aci != null) ? ((Float) aci.getAttribute(TextAttribute.SIZE)).doubleValue() : 0d;
+            double lineHeight = (aci != null) ? ((Float) aci.getAttribute(LINE_HEIGHT)).doubleValue() : fontSize * 1.1f;
+            return computeLineHeightBounds(firstPosition, ascent, emHeight, lineHeight, bbox.getWidth());
+        } else {
+            return new Rectangle2D.Double();
+        }
+    }
+
+    private Rectangle2D computeBBoxBounds(Rectangle2D bbox) {
+        return bbox;
+    }
+
+    private Rectangle2D computeLineHeightBounds(
+        Point2D position, double ascent, double emHeight, double lineHeight, double width) {
+        double x = position.getX();
+        double y = position.getY() - (ascent / emHeight) * lineHeight;
+        double w = width;
+        double h = lineHeight;
+        return new Rectangle2D.Double(x, y, w, h);
+    }
+
+    private void adjustForOutline(Rectangle2D b, float[] outline) {
+        if (outline != null) {
+            double x = b.getX();
+            double y = b.getY();
+            double w = b.getWidth();
+            double h = b.getHeight();
+            x -= outline[3];
+            y -= outline[0];
+            w += outline[1] + outline[3];
+            h += outline[0] + outline[2];
+            b.setFrame(x, y, w, h);
+        }
+    }
+
+    /**
      * Paints decorations of the specified type.
      */
     protected void paintDecorations(List textRuns,
diff --git a/batik-bridge/src/main/java/org/apache/batik/bridge/TextNode.java b/batik-bridge/src/main/java/org/apache/batik/bridge/TextNode.java
index d6938ca..0270319 100644
--- a/batik-bridge/src/main/java/org/apache/batik/bridge/TextNode.java
+++ b/batik-bridge/src/main/java/org/apache/batik/bridge/TextNode.java
@@ -27,6 +27,7 @@
 import java.text.AttributedCharacterIterator;
 import java.text.CharacterIterator;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.batik.gvt.AbstractGraphicsNode;
 import org.apache.batik.gvt.Selectable;
@@ -63,6 +64,11 @@
     protected String text;
 
     /**
+     * Attibutes that apply to text node as a whole (not to individual text runs).
+     */
+    protected Map textAttributes;
+
+    /**
      * The begin mark.
      */
     protected Mark beginMark = null;
@@ -165,6 +171,13 @@
     }
 
     /**
+     * Returns the top level text attributes of text node.
+     */
+    public Map getTextAttributes() {
+        return textAttributes;
+    }
+
+    /**
      * Sets the location of this text node.
      *
      * @param newLocation the new location of this text node
@@ -193,19 +206,25 @@
         fireGraphicsNodeChangeCompleted();
     }
                                   
-
     /**
      * Sets the attributed character iterator of this text node.
      *
      * @param newAci the new attributed character iterator
+     * @param textAttributes top-level text node attributes map
      */
     public void setAttributedCharacterIterator
         (AttributedCharacterIterator newAci) {
+        this.setAttributedCharacterIterator(newAci, null);
+    }
+
+    public void setAttributedCharacterIterator
+        (AttributedCharacterIterator newAci, Map textAttributes) {
         fireGraphicsNodeChangeStarted();
         invalidateGeometryCache();
         this.aci = newAci;
-        text = null;
-        textRuns = null;
+        this.text = null;
+        this.textAttributes = textAttributes;
+        this.textRuns = null;
         fireGraphicsNodeChangeCompleted();
     }
 
@@ -538,6 +557,11 @@
             }
         }
     }
+
+    public enum BackgroundMode {
+        BBOX,
+        LINE_HEIGHT;
+    };
 }
 
 
diff --git a/batik-bridge/src/main/java/org/apache/batik/bridge/TextUtilities.java b/batik-bridge/src/main/java/org/apache/batik/bridge/TextUtilities.java
index bb05ec3..952d374 100644
--- a/batik-bridge/src/main/java/org/apache/batik/bridge/TextUtilities.java
+++ b/batik-bridge/src/main/java/org/apache/batik/bridge/TextUtilities.java
@@ -22,13 +22,21 @@
 import java.util.ArrayList;
 import java.util.StringTokenizer;
 
+
+
 import org.apache.batik.css.engine.SVGCSSEngine;
+import org.apache.batik.css.engine.value.ComputedValue;
 import org.apache.batik.css.engine.value.Value;
+import org.apache.batik.css.engine.value.ValueConstants;
+import org.apache.batik.css.engine.value.svg12.LineHeightValue;
+import org.apache.batik.css.engine.value.svg12.SVG12ValueConstants;
 import org.apache.batik.util.CSSConstants;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.css.CSSPrimitiveValue;
+import org.apache.batik.gvt.text.TextPaintInfo;
 
+import org.apache.batik.css.engine.value.StringValue;
 /**
  * A collection of utility method for text.
  *
@@ -145,6 +153,30 @@
     }
 
     /**
+     * Converts the line-height CSS value to a float value.
+     * @param e the element
+     */
+    public static Float convertLineHeight(Element e, int lineHeightIndex, float fontSize) {
+        Value v = CSSUtilities.getComputedStyle(e, lineHeightIndex);
+        if ((v == ValueConstants.INHERIT_VALUE) ||
+            (v == SVG12ValueConstants.NORMAL_VALUE)) {
+            return fontSize*1.1f;
+        }
+        float lineHeight = fontSize;
+        if (v instanceof ComputedValue)
+            v = ((ComputedValue)v).getComputedValue();
+        if (v instanceof LineHeightValue) {
+            lineHeight = v.getFloatValue();
+            if (((LineHeightValue)v).getFontSizeRelative())
+                lineHeight *= fontSize;
+        } else if (v.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) {
+            if (v.getStringValue().equals(CSS_NORMAL_VALUE))
+                lineHeight = fontSize * 1.1f;
+        }
+        return Float.valueOf(lineHeight);
+    }
+
+    /**
      * Converts the font-style CSS value to a float value.
      * @param e the element
      */
@@ -262,6 +294,43 @@
     }
 
     /**
+     * Converts the background-mode CSS value to a TextNode.BackgroundMode.
+     * @param e the element
+     */
+    public static StringValue convertBackgroundMode(Element e) {
+        Value v = CSSUtilities.getComputedStyle
+            (e, SVGCSSEngine.BACKGROUND_MODE_INDEX);
+        switch (v.getStringValue().charAt(0)) {
+        case 'b':
+            return new StringValue(CSSPrimitiveValue.CSS_IDENT,TextPaintInfo.BBOX);
+        case 'l':
+        default:
+            return new StringValue(CSSPrimitiveValue.CSS_IDENT,TextPaintInfo.LINE_HEIGHT);
+        }
+    }
+
+    /**
+     * Converts the background-outline CSS value to a floats[] instance.
+     * @param e the element
+     */
+    public static float[] convertBackgroundOutline(Element e) {
+        Value v;
+        v = CSSUtilities.getComputedStyle(e, SVGCSSEngine.BACKGROUND_OUTLINE_TOP_INDEX);
+        float top = v.getFloatValue();
+
+        v = CSSUtilities.getComputedStyle(e, SVGCSSEngine.BACKGROUND_OUTLINE_RIGHT_INDEX);
+        float right = v.getFloatValue();
+
+        v = CSSUtilities.getComputedStyle(e, SVGCSSEngine.BACKGROUND_OUTLINE_BOTTOM_INDEX);
+        float bottom = v.getFloatValue();
+
+        v = CSSUtilities.getComputedStyle(e, SVGCSSEngine.BACKGROUND_OUTLINE_LEFT_INDEX);
+        float left = v.getFloatValue();
+
+        return new float[] { top, right, bottom, left };
+    }
+
+    /**
      * Converts a baseline-shift CSS value to a value usable as a text
      * attribute, or null.
      * @param e the element
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/SVG12CSSEngine.java b/batik-css/src/main/java/org/apache/batik/css/engine/SVG12CSSEngine.java
index cf9ad99..590061a 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/SVG12CSSEngine.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/SVG12CSSEngine.java
@@ -22,7 +22,6 @@
 import org.apache.batik.css.engine.value.ValueManager;
 import org.apache.batik.css.engine.value.svg.SVGColorManager;
 import org.apache.batik.css.engine.value.svg.OpacityManager;
-import org.apache.batik.css.engine.value.svg12.LineHeightManager;
 import org.apache.batik.css.engine.value.svg12.MarginLengthManager;
 import org.apache.batik.css.engine.value.svg12.MarginShorthandManager;
 import org.apache.batik.css.engine.value.svg12.TextAlignManager;
@@ -55,7 +54,6 @@
               SVG_VALUE_MANAGERS,
               SVG_SHORTHAND_MANAGERS,
               ctx);
-        lineHeightIndex = LINE_HEIGHT_INDEX;
     }
 
     /**
@@ -77,14 +75,12 @@
               mergeArrays(SVG_VALUE_MANAGERS, vms),
               mergeArrays(SVG_SHORTHAND_MANAGERS, sms),
               ctx);
-        lineHeightIndex = LINE_HEIGHT_INDEX;
     }
 
     /**
      * The value managers for SVG.
      */
     public static final ValueManager[] SVG_VALUE_MANAGERS = {
-        new LineHeightManager  (),
         new MarginLengthManager(SVG12CSSConstants.CSS_INDENT_PROPERTY),
         new MarginLengthManager(SVG12CSSConstants.CSS_MARGIN_BOTTOM_PROPERTY),
         new MarginLengthManager(SVG12CSSConstants.CSS_MARGIN_LEFT_PROPERTY),
@@ -106,8 +102,7 @@
     //
     // The property indexes.
     //
-    public static final int LINE_HEIGHT_INDEX   = SVGCSSEngine.FINAL_INDEX+1;
-    public static final int INDENT_INDEX        = LINE_HEIGHT_INDEX+1;
+    public static final int INDENT_INDEX        = SVGCSSEngine.FINAL_INDEX+1;
     public static final int MARGIN_BOTTOM_INDEX = INDENT_INDEX+1;
     public static final int MARGIN_LEFT_INDEX   = MARGIN_BOTTOM_INDEX+1;
     public static final int MARGIN_RIGHT_INDEX  = MARGIN_LEFT_INDEX+1;
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/SVGCSSEngine.java b/batik-css/src/main/java/org/apache/batik/css/engine/SVGCSSEngine.java
index 7ee8995..0e54353 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/SVGCSSEngine.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/SVGCSSEngine.java
@@ -21,6 +21,9 @@
 import org.apache.batik.css.engine.value.ShorthandManager;
 import org.apache.batik.css.engine.value.ValueConstants;
 import org.apache.batik.css.engine.value.ValueManager;
+import org.apache.batik.css.engine.value.css2.BackgroundModeManager;
+import org.apache.batik.css.engine.value.css2.BackgroundOutlineShorthandManager;
+import org.apache.batik.css.engine.value.css2.BackgroundOutlineLengthManager;
 import org.apache.batik.css.engine.value.css2.ClipManager;
 import org.apache.batik.css.engine.value.css2.CursorManager;
 import org.apache.batik.css.engine.value.css2.DirectionManager;
@@ -33,6 +36,7 @@
 import org.apache.batik.css.engine.value.css2.FontStyleManager;
 import org.apache.batik.css.engine.value.css2.FontVariantManager;
 import org.apache.batik.css.engine.value.css2.FontWeightManager;
+import org.apache.batik.css.engine.value.css2.LineHeightManager;
 import org.apache.batik.css.engine.value.css2.OverflowManager;
 import org.apache.batik.css.engine.value.css2.SrcManager;
 import org.apache.batik.css.engine.value.css2.TextDecorationManager;
@@ -109,8 +113,6 @@
               true,
               null,
               ctx);
-        // SVG defines line-height to be font-size.
-        lineHeightIndex = fontSizeIndex;
     }
 
     /**
@@ -139,8 +141,6 @@
               true,
               null,
               ctx);
-        // SVG defines line-height to be font-size.
-        lineHeightIndex = fontSizeIndex;
     }
 
     protected SVGCSSEngine(Document doc,
@@ -160,8 +160,6 @@
               mergeArrays(SVG_VALUE_MANAGERS, vms),
               mergeArrays(SVG_SHORTHAND_MANAGERS, sms),
               pe, sns, sln, cns, cln, hints, hintsNS, ctx);
-        // SVG defines line-height to be font-size.
-        lineHeightIndex = fontSizeIndex;
     }
 
 
@@ -193,6 +191,12 @@
      */
     public static final ValueManager[] SVG_VALUE_MANAGERS = {
         new AlignmentBaselineManager(),
+        new SVGColorManager(CSSConstants.CSS_BACKGROUND_COLOR_PROPERTY, ValueConstants.TRANSPARENT_VALUE),
+        new BackgroundModeManager(),
+        new BackgroundOutlineLengthManager(CSSConstants.CSS_BACKGROUND_OUTLINE_BOTTOM_PROPERTY),
+        new BackgroundOutlineLengthManager(CSSConstants.CSS_BACKGROUND_OUTLINE_LEFT_PROPERTY),
+        new BackgroundOutlineLengthManager(CSSConstants.CSS_BACKGROUND_OUTLINE_RIGHT_PROPERTY),
+        new BackgroundOutlineLengthManager(CSSConstants.CSS_BACKGROUND_OUTLINE_TOP_PROPERTY),
         new BaselineShiftManager(),
         new ClipManager(),
         new ClipPathManager(),
@@ -233,6 +237,7 @@
         new SpacingManager(CSSConstants.CSS_LETTER_SPACING_PROPERTY),
         new SVGColorManager(CSSConstants.CSS_LIGHTING_COLOR_PROPERTY,
                             ValueConstants.WHITE_RGB_VALUE),
+        new LineHeightManager(),
         new MarkerManager(CSSConstants.CSS_MARKER_END_PROPERTY),
 
         new MarkerManager(CSSConstants.CSS_MARKER_MID_PROPERTY),
@@ -271,6 +276,7 @@
      * The shorthand managers for SVG.
      */
     public static final ShorthandManager[] SVG_SHORTHAND_MANAGERS = {
+        new BackgroundOutlineShorthandManager(),
         new FontShorthandManager(),
         new MarkerShorthandManager(),
     };
@@ -279,8 +285,14 @@
     // The property indexes.
     //
     public static final int ALIGNMENT_BASELINE_INDEX = 0;
+    public static final int BACKGROUND_COLOR_INDEX = ALIGNMENT_BASELINE_INDEX + 1;
+    public static final int BACKGROUND_MODE_INDEX = BACKGROUND_COLOR_INDEX + 1;
+    public static final int BACKGROUND_OUTLINE_BOTTOM_INDEX = BACKGROUND_MODE_INDEX + 1;
+    public static final int BACKGROUND_OUTLINE_LEFT_INDEX = BACKGROUND_OUTLINE_BOTTOM_INDEX + 1;
+    public static final int BACKGROUND_OUTLINE_RIGHT_INDEX = BACKGROUND_OUTLINE_LEFT_INDEX + 1;
+    public static final int BACKGROUND_OUTLINE_TOP_INDEX = BACKGROUND_OUTLINE_RIGHT_INDEX + 1;
     public static final int BASELINE_SHIFT_INDEX =
-        ALIGNMENT_BASELINE_INDEX + 1;
+        BACKGROUND_OUTLINE_TOP_INDEX + 1;
     public static final int CLIP_INDEX = BASELINE_SHIFT_INDEX + 1;
     public static final int CLIP_PATH_INDEX = CLIP_INDEX +1;
     public static final int CLIP_RULE_INDEX = CLIP_PATH_INDEX + 1;
@@ -329,7 +341,8 @@
     public static final int KERNING_INDEX = IMAGE_RENDERING_INDEX + 1;
     public static final int LETTER_SPACING_INDEX = KERNING_INDEX + 1;
     public static final int LIGHTING_COLOR_INDEX = LETTER_SPACING_INDEX + 1;
-    public static final int MARKER_END_INDEX = LIGHTING_COLOR_INDEX + 1;
+    public static final int LINE_HEIGHT_INDEX = LIGHTING_COLOR_INDEX + 1;
+    public static final int MARKER_END_INDEX = LINE_HEIGHT_INDEX + 1;
 
 
     public static final int MARKER_MID_INDEX = MARKER_END_INDEX + 1;
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/AbstractColorManager.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/AbstractColorManager.java
index 488fd26..2cf3e82 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/value/AbstractColorManager.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/AbstractColorManager.java
@@ -68,6 +68,8 @@
                    ValueConstants.SILVER_VALUE);
         values.put(CSSConstants.CSS_TEAL_VALUE,
                    ValueConstants.TEAL_VALUE);
+        values.put(CSSConstants.CSS_TRANSPARENT_VALUE,
+                   ValueConstants.TRANSPARENT_VALUE);
         values.put(CSSConstants.CSS_WHITE_VALUE,
                    ValueConstants.WHITE_VALUE);
         values.put(CSSConstants.CSS_YELLOW_VALUE,
@@ -166,6 +168,8 @@
                            ValueConstants.BLUE_RGB_VALUE);
         computedValues.put(CSSConstants.CSS_TEAL_VALUE,
                            ValueConstants.TEAL_RGB_VALUE);
+        computedValues.put(CSSConstants.CSS_TRANSPARENT_VALUE,
+                           ValueConstants.TRANSPARENT_RGB_VALUE);
         computedValues.put(CSSConstants.CSS_AQUA_VALUE,
                            ValueConstants.AQUA_RGB_VALUE);
     }
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/AbstractValue.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/AbstractValue.java
index 2829747..488bdfa 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/value/AbstractValue.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/AbstractValue.java
@@ -79,6 +79,13 @@
     }
 
     /**
+     * Implements {@link Value#getAlpha()}.
+     */
+    public Value getAlpha() throws DOMException {
+        throw createDOMException();
+    }
+
+    /**
      * Implements {@link Value#getLength()}.
      */
     public int getLength() throws DOMException {
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/ComputedValue.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/ComputedValue.java
index fc9b300..d0b5578 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/value/ComputedValue.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/ComputedValue.java
@@ -124,6 +124,13 @@
     }
 
     /**
+     * Implements {@link Value#getGreen()}.
+     */
+    public Value getAlpha() throws DOMException {
+        return computedValue.getAlpha();
+    }
+
+    /**
      * Implements {@link Value#getLength()}.
      */
     public int getLength() throws DOMException {
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/RGBAColorValue.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/RGBAColorValue.java
new file mode 100644
index 0000000..d93a73a
--- /dev/null
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/RGBAColorValue.java
@@ -0,0 +1,61 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.batik.css.engine.value;
+
+import org.w3c.dom.DOMException;
+
+/**
+ * This class represents RGBA colors.
+ *
+ * @author <a href="mailto:gadams@apache.org">Glenn Adams</a>
+ * @version $Id$
+ */
+public class RGBAColorValue extends RGBColorValue {
+
+    /**
+     * The alpha component.
+     */
+    protected Value alpha;
+
+    /**
+     * Creates a new RGBAColorValue.
+     */
+    public RGBAColorValue(Value r, Value g, Value b, Value a) {
+        super(r, g, b);
+        alpha = a;
+    }
+
+    /**
+     * A string representation of the current value.
+     */
+    public String getCssText() {
+        return "rgba(" +
+            red.getCssText() + ", " +
+            green.getCssText() + ", " +
+            blue.getCssText() + ", " +
+            alpha.getCssText() + ')';
+    }
+
+    /**
+     * Implements {@link Value#getAlpha()}.
+     */
+    public Value getAlpha() throws DOMException {
+        return alpha;
+    }
+}
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/Value.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/Value.java
index 114f94f..fed7f54 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/value/Value.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/Value.java
@@ -84,6 +84,14 @@
     Value getBlue() throws DOMException;
 
     /**
+     * The alpha value of the RGBA color. 
+     * @exception DOMException
+     *    INVALID_ACCESS_ERR: Raised if the value doesn't contain a RGB
+     *    color value. 
+     */
+    Value getAlpha() throws DOMException;
+
+    /**
      * The number of <code>CSSValues</code> in the list. The range of valid 
      * values of the indices is <code>0</code> to <code>length-1</code> 
      * inclusive.
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/ValueConstants.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/ValueConstants.java
index aeaeb1d..cdc75fa 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/value/ValueConstants.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/ValueConstants.java
@@ -772,6 +772,13 @@
                         CSSConstants.CSS_TEAL_VALUE);
 
     /**
+     * The 'transparent' color name.
+     */
+    Value TRANSPARENT_VALUE =
+        new StringValue(CSSPrimitiveValue.CSS_IDENT,
+                        CSSConstants.CSS_TRANSPARENT_VALUE);
+
+    /**
      * The 'white' color name.
      */
     Value WHITE_VALUE =
@@ -1073,6 +1080,12 @@
         new RGBColorValue(NUMBER_0, NUMBER_128, NUMBER_128);
 
     /**
+     * The 'transparent' RGB color.
+     */
+    Value TRANSPARENT_RGB_VALUE =
+        new RGBAColorValue(NUMBER_0, NUMBER_0, NUMBER_0, NUMBER_0);
+
+    /**
      * The 'aqua' RGB color.
      */
     Value AQUA_RGB_VALUE =
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/BackgroundModeManager.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/BackgroundModeManager.java
new file mode 100644
index 0000000..c95c500
--- /dev/null
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/BackgroundModeManager.java
@@ -0,0 +1,97 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.batik.css.engine.value.css2;
+
+import org.apache.batik.css.engine.value.IdentifierManager;
+import org.apache.batik.css.engine.value.StringMap;
+import org.apache.batik.css.engine.value.Value;
+import org.apache.batik.css.engine.value.ValueManager;
+import org.apache.batik.css.engine.value.svg.SVGValueConstants;
+import org.apache.batik.util.CSSConstants;
+import org.apache.batik.util.SVGTypes;
+
+/**
+ * This class provides a manager for the 'background-mode' property values.
+ *
+ * @author <a href="mailto:gadams@apache.org">Glenn Adams</a>
+ * @version $Id$
+ */
+public class BackgroundModeManager extends IdentifierManager {
+
+    /**
+     * The identifier values.
+     */
+    protected static final StringMap values = new StringMap();
+    static {
+        values.put(CSSConstants.CSS_BBOX_VALUE, SVGValueConstants.BBOX_VALUE);
+        values.put(CSSConstants.CSS_LINE_HEIGHT_VALUE, SVGValueConstants.LINE_HEIGHT_VALUE);
+    }
+
+    /**
+     * Implements {@link
+     * org.apache.batik.css.engine.value.ValueManager#isInheritedProperty()}.
+     */
+    public boolean isInheritedProperty() {
+        return true;
+    }
+
+    /**
+     * Implements {@link ValueManager#isAnimatableProperty()}.
+     */
+    public boolean isAnimatableProperty() {
+        return false;
+    }
+
+    /**
+     * Implements {@link ValueManager#isAdditiveProperty()}.
+     */
+    public boolean isAdditiveProperty() {
+        return false;
+    }
+
+    /**
+     * Implements {@link ValueManager#getPropertyType()}.
+     */
+    public int getPropertyType() {
+        return SVGTypes.TYPE_IDENT;
+    }
+
+    /**
+     * Implements {@link
+     * org.apache.batik.css.engine.value.ValueManager#getPropertyName()}.
+     */
+    public String getPropertyName() {
+        return CSSConstants.CSS_BACKGROUND_MODE_PROPERTY;
+    }
+
+    /**
+     * Implements {@link
+     * org.apache.batik.css.engine.value.ValueManager#getDefaultValue()}.
+     */
+    public Value getDefaultValue() {
+        return SVGValueConstants.LINE_HEIGHT_VALUE;
+    }
+
+    /**
+     * Implements {@link IdentifierManager#getIdentifiers()}.
+     */
+    public StringMap getIdentifiers() {
+        return values;
+    }
+}
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/BackgroundOutlineLengthManager.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/BackgroundOutlineLengthManager.java
new file mode 100644
index 0000000..e450b3b
--- /dev/null
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/BackgroundOutlineLengthManager.java
@@ -0,0 +1,107 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.batik.css.engine.value.css2;
+
+import org.apache.batik.css.engine.CSSEngine;
+import org.apache.batik.css.engine.value.LengthManager;
+import org.apache.batik.css.engine.value.Value;
+import org.apache.batik.css.engine.value.ValueConstants;
+import org.apache.batik.css.engine.value.ValueManager;
+import org.apache.batik.util.SVGTypes;
+
+import org.w3c.css.sac.LexicalUnit;
+import org.w3c.dom.DOMException;
+
+/**
+ * This class provides a factory for the 'background-outline-*' properties values.
+ *
+ * @author <a href="mailto:gadams@apache.org">Glenn Adams</a>
+ * @version $Id$
+ */
+public class BackgroundOutlineLengthManager extends LengthManager {
+
+    protected String  prop;
+
+    public BackgroundOutlineLengthManager(String prop) {
+        this.prop = prop;
+    }
+    
+    /**
+     * Implements {@link ValueManager#isInheritedProperty()}.
+     */
+    public boolean isInheritedProperty() {
+        return false;
+    }
+
+    /**
+     * Implements {@link ValueManager#isAnimatableProperty()}.
+     */
+    public boolean isAnimatableProperty() {
+        return true;
+    }
+
+    /**
+     * Implements {@link ValueManager#isAdditiveProperty()}.
+     */
+    public boolean isAdditiveProperty() {
+        return true;
+    }
+
+    /**
+     * Implements {@link ValueManager#getPropertyType()}.
+     */
+    public int getPropertyType() {
+        return SVGTypes.TYPE_LENGTH_OR_INHERIT;
+    }
+
+    /**
+     * Implements {@link ValueManager#getPropertyName()}.
+     */
+    public String getPropertyName() {
+        return prop;
+    }
+    
+    /**
+     * Implements {@link ValueManager#getDefaultValue()}.
+     */
+    public Value getDefaultValue() {
+        return ValueConstants.NUMBER_0;
+    }
+
+    /**
+     * Implements {@link ValueManager#createValue(LexicalUnit,CSSEngine)}.
+     */
+    public Value createValue(LexicalUnit lu, CSSEngine engine)
+        throws DOMException {
+        if (lu.getLexicalUnitType() == LexicalUnit.SAC_INHERIT) {
+            return ValueConstants.INHERIT_VALUE;
+        }
+        return super.createValue(lu, engine);
+    }
+
+
+    /**
+     * Indicates the orientation of the property associated with
+     * this manager.
+     */
+    protected int getOrientation() {
+        // background outlines are always wrt to block width, event for top/bottom.
+        return HORIZONTAL_ORIENTATION;
+    }
+}
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/BackgroundOutlineShorthandManager.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/BackgroundOutlineShorthandManager.java
new file mode 100644
index 0000000..35c07b4
--- /dev/null
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/BackgroundOutlineShorthandManager.java
@@ -0,0 +1,95 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.batik.css.engine.value.css2;
+
+import org.apache.batik.css.engine.CSSEngine;
+import org.apache.batik.css.engine.value.AbstractValueFactory;
+import org.apache.batik.css.engine.value.ShorthandManager;
+import org.apache.batik.css.engine.value.ValueManager;
+import org.apache.batik.util.CSSConstants;
+import org.w3c.css.sac.LexicalUnit;
+import org.w3c.dom.DOMException;
+
+/**
+ * This class represents an object which provide support for the
+ * 'background-outline' shorthand property.
+ *
+ * @author <a href="mailto:gadams@apache.org">Glenn Adams</a>
+ * @version $Id$
+ */
+public class BackgroundOutlineShorthandManager
+    extends AbstractValueFactory
+    implements ShorthandManager {
+
+    public BackgroundOutlineShorthandManager() { }
+    
+    /**
+     * Implements {@link ValueManager#getPropertyName()}.
+     */
+    public String getPropertyName() {
+        return CSSConstants.CSS_BACKGROUND_OUTLINE_PROPERTY;
+    }
+    
+    /**
+     * Implements {@link ShorthandManager#isAnimatableProperty()}.
+     */
+    public boolean isAnimatableProperty() {
+        return true;
+    }
+
+    /**
+     * Implements {@link ShorthandManager#isAdditiveProperty()}.
+     */
+    public boolean isAdditiveProperty() {
+        return false;
+    }
+
+    /**
+     * Implements {@link ShorthandManager#setValues(CSSEngine,ShorthandManager.PropertyHandler,LexicalUnit,boolean)}.
+     */
+    public void setValues(CSSEngine eng,
+                          ShorthandManager.PropertyHandler ph,
+                          LexicalUnit lu,
+                          boolean imp)
+        throws DOMException {
+        if (lu.getLexicalUnitType() == LexicalUnit.SAC_INHERIT)
+            return;
+
+        LexicalUnit []lus  = new LexicalUnit[4];
+        int cnt=0;
+        while (lu != null) {
+            if (cnt == 4)
+                throw createInvalidLexicalUnitDOMException
+                    (lu.getLexicalUnitType());
+            lus[cnt++] = lu;
+            lu = lu.getNextLexicalUnit();
+        }
+        switch (cnt) {
+        case 1: lus[3] = lus[2] = lus[1] = lus[0]; break;
+        case 2: lus[2] = lus[0];  lus[3] = lus[1]; break;
+        case 3: lus[3] = lus[1]; break;
+        default:
+        }
+
+        ph.property(CSSConstants.CSS_BACKGROUND_OUTLINE_TOP_PROPERTY,    lus[0], imp);
+        ph.property(CSSConstants.CSS_BACKGROUND_OUTLINE_RIGHT_PROPERTY,  lus[1], imp);
+        ph.property(CSSConstants.CSS_BACKGROUND_OUTLINE_BOTTOM_PROPERTY, lus[2], imp);
+        ph.property(CSSConstants.CSS_BACKGROUND_OUTLINE_LEFT_PROPERTY,   lus[3], imp);
+    }
+}
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/svg12/LineHeightManager.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/LineHeightManager.java
similarity index 91%
rename from batik-css/src/main/java/org/apache/batik/css/engine/value/svg12/LineHeightManager.java
rename to batik-css/src/main/java/org/apache/batik/css/engine/value/css2/LineHeightManager.java
index 60e8b49..e767977 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/value/svg12/LineHeightManager.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/LineHeightManager.java
@@ -16,8 +16,7 @@
    limitations under the License.
 
  */
-
-package org.apache.batik.css.engine.value.svg12;
+package org.apache.batik.css.engine.value.css2;
 
 import org.apache.batik.css.engine.CSSEngine;
 import org.apache.batik.css.engine.CSSStylableElement;
@@ -25,8 +24,9 @@
 import org.apache.batik.css.engine.value.LengthManager;
 import org.apache.batik.css.engine.value.FloatValue;
 import org.apache.batik.css.engine.value.Value;
+import org.apache.batik.css.engine.value.ValueConstants;
 import org.apache.batik.css.engine.value.ValueManager;
-import org.apache.batik.util.SVG12CSSConstants;
+import org.apache.batik.util.CSSConstants;
 import org.apache.batik.util.SVGTypes;
 
 import org.w3c.css.sac.LexicalUnit;
@@ -76,14 +76,14 @@
      * Implements {@link ValueManager#getPropertyName()}.
      */
     public String getPropertyName() {
-        return SVG12CSSConstants.CSS_LINE_HEIGHT_PROPERTY;
+        return CSSConstants.CSS_LINE_HEIGHT_PROPERTY;
     }
 
     /**
      * Implements {@link ValueManager#getDefaultValue()}.
      */
     public Value getDefaultValue() {
-        return SVG12ValueConstants.NORMAL_VALUE;
+        return ValueConstants.NORMAL_VALUE;
     }
 
     /**
@@ -94,11 +94,11 @@
 
         switch (lu.getLexicalUnitType()) {
         case LexicalUnit.SAC_INHERIT:
-            return SVG12ValueConstants.INHERIT_VALUE;
+            return ValueConstants.INHERIT_VALUE;
         case LexicalUnit.SAC_IDENT: {
             String s = lu.getStringValue().toLowerCase();
-            if (SVG12CSSConstants.CSS_NORMAL_VALUE.equals(s))
-                return SVG12ValueConstants.NORMAL_VALUE;
+            if (CSSConstants.CSS_NORMAL_VALUE.equals(s))
+                return ValueConstants.NORMAL_VALUE;
             throw createInvalidIdentifierDOMException(lu.getStringValue());
         }
         default:
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/LineHeightValue.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/LineHeightValue.java
new file mode 100644
index 0000000..3ec1379
--- /dev/null
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/css2/LineHeightValue.java
@@ -0,0 +1,52 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.batik.css.engine.value.css2;
+
+import org.apache.batik.css.engine.value.FloatValue;
+
+/**
+ * This class represents line-height values.  These are basically
+ * FloatValues except that it may be 'font-size' relative.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id$
+ */
+public class LineHeightValue extends FloatValue {
+    
+    /**
+     * True if the line-height is relative to the font-size
+     */
+    protected boolean fontSizeRelative;
+
+    /**
+     * Creates a new value.
+     */
+    public LineHeightValue(short unitType, float floatValue, 
+                           boolean fontSizeRelative) {
+        super(unitType, floatValue);
+        this.fontSizeRelative   = fontSizeRelative;
+    }
+
+    /**
+     * The type of the value.
+     */
+    public boolean getFontSizeRelative() {
+        return fontSizeRelative;
+    }
+}
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/svg/ColorManager.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/svg/ColorManager.java
index f02dbd1..f89c2f9 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/value/svg/ColorManager.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/svg/ColorManager.java
@@ -342,6 +342,8 @@
                            SVGValueConstants.BLUE_RGB_VALUE);
         computedValues.put(CSSConstants.CSS_TEAL_VALUE,
                            SVGValueConstants.TEAL_RGB_VALUE);
+        computedValues.put(CSSConstants.CSS_TRANSPARENT_VALUE,
+                           SVGValueConstants.TRANSPARENT_RGB_VALUE);
         computedValues.put(CSSConstants.CSS_AQUA_VALUE,
                            SVGValueConstants.AQUA_RGB_VALUE);
 
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/svg/SVGValueConstants.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/svg/SVGValueConstants.java
index 89ed791..57e3f55 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/value/svg/SVGValueConstants.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/svg/SVGValueConstants.java
@@ -719,6 +719,13 @@
                         CSSConstants.CSS_BASELINE_VALUE);
     
     /**
+     * The 'bbox' keyword.
+     */
+    Value BBOX_VALUE =
+        new StringValue(CSSPrimitiveValue.CSS_IDENT,
+                        CSSConstants.CSS_BBOX_VALUE);
+    
+    /**
      * The 'before-edge' keyword.
      */
     Value BEFORE_EDGE_VALUE =
@@ -810,6 +817,13 @@
                         CSSConstants.CSS_LINEARRGB_VALUE);
     
     /**
+     * The 'line-height' keyword (used with background-mode property).
+     */
+    Value LINE_HEIGHT_VALUE =
+        new StringValue(CSSPrimitiveValue.CSS_IDENT,
+                        CSSConstants.CSS_LINE_HEIGHT_VALUE);
+    
+    /**
      * The 'lr' keyword.
      */
     Value LR_VALUE =
diff --git a/batik-css/src/main/java/org/apache/batik/css/engine/value/svg12/LineHeightValue.java b/batik-css/src/main/java/org/apache/batik/css/engine/value/svg12/LineHeightValue.java
index 80a4493..c20bebf 100644
--- a/batik-css/src/main/java/org/apache/batik/css/engine/value/svg12/LineHeightValue.java
+++ b/batik-css/src/main/java/org/apache/batik/css/engine/value/svg12/LineHeightValue.java
@@ -18,8 +18,6 @@
  */
 package org.apache.batik.css.engine.value.svg12;
 
-import org.apache.batik.css.engine.value.FloatValue;
-
 /**
  * This class represents line-height values.  These are basically
  * FloatValues except that it may be 'font-size' relative.
@@ -27,26 +25,8 @@
  * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
  * @version $Id$
  */
-public class LineHeightValue extends FloatValue {
-    
-    /**
-     * True if the line-height is relative to the font-size
-     */
-    protected boolean fontSizeRelative;
-
-    /**
-     * Creates a new value.
-     */
-    public LineHeightValue(short unitType, float floatValue, 
-                           boolean fontSizeRelative) {
-        super(unitType, floatValue);
-        this.fontSizeRelative   = fontSizeRelative;
-    }
-
-    /**
-     * The type of the value.
-     */
-    public boolean getFontSizeRelative() {
-        return fontSizeRelative;
+public class LineHeightValue extends org.apache.batik.css.engine.value.css2.LineHeightValue {
+    public LineHeightValue(short unitType, float floatValue, boolean fontSizeRelative) {
+        super(unitType, floatValue, fontSizeRelative);
     }
 }
diff --git a/batik-gvt/src/main/java/org/apache/batik/gvt/text/GVTAttributedCharacterIterator.java b/batik-gvt/src/main/java/org/apache/batik/gvt/text/GVTAttributedCharacterIterator.java
index d6792c6..adc1c6e 100644
--- a/batik-gvt/src/main/java/org/apache/batik/gvt/text/GVTAttributedCharacterIterator.java
+++ b/batik-gvt/src/main/java/org/apache/batik/gvt/text/GVTAttributedCharacterIterator.java
@@ -351,6 +351,9 @@
         public static final TextAttribute LANGUAGE =
                                           new TextAttribute("LANGUAGE");
 
+        public static final TextAttribute BACKGROUND_OUTLINE =
+                                          new TextAttribute("BACKGROUND_OUTLINE");
+
         // VALUES
 
         /** Value for WRITING_MODE indicating left-to-right */
diff --git a/batik-gvt/src/main/java/org/apache/batik/gvt/text/TextPaintInfo.java b/batik-gvt/src/main/java/org/apache/batik/gvt/text/TextPaintInfo.java
index 54ab170..555bc56 100644
--- a/batik-gvt/src/main/java/org/apache/batik/gvt/text/TextPaintInfo.java
+++ b/batik-gvt/src/main/java/org/apache/batik/gvt/text/TextPaintInfo.java
@@ -22,6 +22,8 @@
 import java.awt.Paint;
 import java.awt.Stroke;
 
+import org.apache.batik.util.CSSConstants;
+
 /**
  * One line Class Desc
  *
@@ -32,6 +34,8 @@
  */
 public class TextPaintInfo {
     public boolean   visible;
+    public Paint     backgroundPaint;
+    public String    backgroundMode;
     public Paint     fillPaint;
     public Paint     strokePaint;
     public Stroke    strokeStroke;
@@ -51,6 +55,9 @@
 
     public int    startChar, endChar;
 
+    public static final String BBOX = CSSConstants.CSS_BBOX_VALUE;
+    public static final String LINE_HEIGHT = CSSConstants.CSS_LINE_HEIGHT_VALUE;
+    
     public TextPaintInfo() { }
     
     public TextPaintInfo(TextPaintInfo pi) {
@@ -59,6 +66,8 @@
 
     public void set(TextPaintInfo pi) {
         if (pi == null) {
+            this.backgroundPaint = null;
+            this.backgroundMode = null;
             this.fillPaint    = null;
             this.strokePaint  = null;
             this.strokeStroke = null;
@@ -78,6 +87,8 @@
 
             this.visible = false;
         } else {
+            this.backgroundPaint = pi.backgroundPaint;
+            this.backgroundMode = pi.backgroundMode;
             this.fillPaint    = pi.fillPaint;
             this.strokePaint  = pi.strokePaint;
             this.strokeStroke = pi.strokeStroke;
@@ -105,6 +116,12 @@
             return false;
         } else if (tpi2 == null) return false;
 
+        if ((tpi1.backgroundPaint == null) != (tpi2.backgroundPaint == null))
+            return false;
+
+        if ((tpi1.backgroundMode == null) != (tpi2.backgroundMode == null))
+            return false;
+
         if ((tpi1.fillPaint == null) != (tpi2.fillPaint == null))
             return false;
 
diff --git a/batik-svggen/src/main/java/org/apache/batik/svggen/SVGStylingAttributes.java b/batik-svggen/src/main/java/org/apache/batik/svggen/SVGStylingAttributes.java
index 4ec1e06..a8fc078 100644
--- a/batik-svggen/src/main/java/org/apache/batik/svggen/SVGStylingAttributes.java
+++ b/batik-svggen/src/main/java/org/apache/batik/svggen/SVGStylingAttributes.java
@@ -32,6 +32,12 @@
     static Set attrSet = new HashSet();
 
     static {
+        attrSet.add(SVG_BACKGROUND_COLOR_ATTRIBUTE);
+        attrSet.add(SVG_BACKGROUND_MODE_ATTRIBUTE);
+        attrSet.add(SVG_BACKGROUND_OUTLINE_BOTTOM_ATTRIBUTE);
+        attrSet.add(SVG_BACKGROUND_OUTLINE_LEFT_ATTRIBUTE);
+        attrSet.add(SVG_BACKGROUND_OUTLINE_RIGHT_ATTRIBUTE);
+        attrSet.add(SVG_BACKGROUND_OUTLINE_TOP_ATTRIBUTE);
         attrSet.add(SVG_CLIP_PATH_ATTRIBUTE);
         attrSet.add(SVG_COLOR_INTERPOLATION_ATTRIBUTE);
         attrSet.add(SVG_COLOR_RENDERING_ATTRIBUTE);
diff --git a/batik-util/src/main/java/org/apache/batik/util/CSSConstants.java b/batik-util/src/main/java/org/apache/batik/util/CSSConstants.java
index f66e693..df2c933 100644
--- a/batik-util/src/main/java/org/apache/batik/util/CSSConstants.java
+++ b/batik-util/src/main/java/org/apache/batik/util/CSSConstants.java
@@ -36,6 +36,13 @@
     // The CSS property names.
     //
     String CSS_ALIGNMENT_BASELINE_PROPERTY = "alignment-baseline";
+    String CSS_BACKGROUND_COLOR_PROPERTY = "background-color";
+    String CSS_BACKGROUND_MODE_PROPERTY = "background-mode";
+    String CSS_BACKGROUND_OUTLINE_PROPERTY = "background-outline";
+    String CSS_BACKGROUND_OUTLINE_BOTTOM_PROPERTY = "background-outline-bottom";
+    String CSS_BACKGROUND_OUTLINE_LEFT_PROPERTY = "background-outline-left";
+    String CSS_BACKGROUND_OUTLINE_RIGHT_PROPERTY = "background-outline-right";
+    String CSS_BACKGROUND_OUTLINE_TOP_PROPERTY = "background-outline-top";
     String CSS_BASELINE_SHIFT_PROPERTY = "baseline-shift";
     String CSS_CLIP_PROPERTY = "clip";
     String CSS_CLIP_PATH_PROPERTY = "clip-path";
@@ -118,6 +125,7 @@
     String CSS_AZURE_VALUE = "azure";
     String CSS_BACKGROUND_VALUE = "background";
     String CSS_BASELINE_VALUE = "baseline";
+    String CSS_BBOX_VALUE = "bbox";
     String CSS_BEFORE_EDGE_VALUE = "before-edge";
     String CSS_BEIGE_VALUE = "beige";
     String CSS_BEVEL_VALUE = "bevel";
@@ -252,6 +260,7 @@
     String CSS_LIGHTYELLOW_VALUE = "lightyellow";
     String CSS_LIMEGREEN_VALUE = "limegreen";
     String CSS_LIME_VALUE = "lime";
+    String CSS_LINE_HEIGHT_VALUE = "line-height";
     String CSS_LINEARRGB_VALUE = "linearrgb";
     String CSS_LINEN_VALUE = "linen";
     String CSS_LINE_THROUGH_VALUE = "line-through";
@@ -377,6 +386,7 @@
     String CSS_TB_RL_VALUE = "tb-rl";
     String CSS_TB_VALUE = "tb";
     String CSS_TEAL_VALUE = "teal";
+    String CSS_TRANSPARENT_VALUE = "transparent";
     String CSS_TEXT_AFTER_EDGE_VALUE = "text-after-edge";
     String CSS_TEXT_BEFORE_EDGE_VALUE = "text-before-edge";
     String CSS_TEXT_BOTTOM_VALUE = "text-bottom";
diff --git a/batik-util/src/main/java/org/apache/batik/util/SVG12CSSConstants.java b/batik-util/src/main/java/org/apache/batik/util/SVG12CSSConstants.java
index 19b57d4..6331d8d 100644
--- a/batik-util/src/main/java/org/apache/batik/util/SVG12CSSConstants.java
+++ b/batik-util/src/main/java/org/apache/batik/util/SVG12CSSConstants.java
@@ -56,7 +56,5 @@
     String CSS_END_VALUE    = "end";
     /** Value for text-align to both edges of region */
     String CSS_FULL_VALUE = "full";
-    /** Value for line-height for 'normal' line height */
-    String CSS_NORMAL_VALUE = "normal";
 
 }
diff --git a/batik-util/src/main/java/org/apache/batik/util/SVGConstants.java b/batik-util/src/main/java/org/apache/batik/util/SVGConstants.java
index d28c9df..823aa16 100644
--- a/batik-util/src/main/java/org/apache/batik/util/SVGConstants.java
+++ b/batik-util/src/main/java/org/apache/batik/util/SVGConstants.java
@@ -440,6 +440,13 @@
     String SVG_ALPHABETIC_ATTRIBUTE = "alphabetic";
     String SVG_ATTRIBUTE_NAME_ATTRIBUTE = "attributeName";
     String SVG_ATTRIBUTE_TYPE_ATTRIBUTE = "attributeType";
+    String SVG_BACKGROUND_COLOR_ATTRIBUTE = CSS_BACKGROUND_COLOR_PROPERTY;
+    String SVG_BACKGROUND_MODE_ATTRIBUTE = CSS_BACKGROUND_MODE_PROPERTY;
+    String SVG_BACKGROUND_OUTLINE_ATTRIBUTE = CSS_BACKGROUND_OUTLINE_PROPERTY;
+    String SVG_BACKGROUND_OUTLINE_BOTTOM_ATTRIBUTE = CSS_BACKGROUND_OUTLINE_BOTTOM_PROPERTY;
+    String SVG_BACKGROUND_OUTLINE_LEFT_ATTRIBUTE = CSS_BACKGROUND_OUTLINE_LEFT_PROPERTY;
+    String SVG_BACKGROUND_OUTLINE_RIGHT_ATTRIBUTE = CSS_BACKGROUND_OUTLINE_RIGHT_PROPERTY;
+    String SVG_BACKGROUND_OUTLINE_TOP_ATTRIBUTE = CSS_BACKGROUND_OUTLINE_TOP_PROPERTY;
     String SVG_BASE_FREQUENCY_ATTRIBUTE = "baseFrequency";
     String SVG_BASE_PROFILE_ATTRIBUTE = "baseProfile";
     String SVG_BEGIN_ATTRIBUTE = "begin";