Index: java/org/apache/fop/fo/flow/Marker.java
===================================================================
--- java/org/apache/fop/fo/flow/Marker.java	(revision 723701)
+++ java/org/apache/fop/fo/flow/Marker.java	(working copy)
@@ -34,6 +34,7 @@
 import org.apache.fop.fo.PropertyListMaker;
 import org.apache.fop.fo.ValidationException;
 import org.apache.fop.fo.properties.Property;
+import org.apache.fop.fo.properties.PropertyCache;
 
 /**
  * Class modelling the fo:marker object.
@@ -361,10 +362,10 @@
     /**
      * Convenience inner class
      */
-    private static final class MarkerAttribute {
+    public static final class MarkerAttribute {
         
-        private static Map attributeCache = 
-            Collections.synchronizedMap(new java.util.WeakHashMap());
+        private static PropertyCache attributeCache =
+                new PropertyCache(MarkerAttribute.class);
 
         protected String namespace;
         protected String qname;
@@ -398,20 +399,27 @@
         private static MarkerAttribute getInstance(
                                             String namespace, String qname,
                                             String name, String value) {
-            MarkerAttribute newInstance = 
-                new MarkerAttribute(namespace, qname, name, value);
-            if (attributeCache.containsKey(newInstance)) {
-                return (MarkerAttribute) attributeCache.get(newInstance);
-            } else {
-                attributeCache.put(newInstance, newInstance);
-                return newInstance;
-            }
+            return attributeCache.fetch(
+                    new MarkerAttribute(namespace, qname, name, value));
         }
         
+        /** {@inheritDoc} */
+        public int hashCode() {
+            int hash = 17;
+            hash = (37 * hash) + (this.namespace == null ? 0 : this.namespace.hashCode());
+            hash = (37 * hash) + (this.qname == null ? 0 : this.qname.hashCode());
+            hash = (37 * hash) + (this.name == null ? 0 : this.name.hashCode());
+            hash = (37 * hash) + (this.value == null ? 0 : this.value.hashCode());
+            return hash;
+        }
+        
         /**
          * {@inheritDoc}
          */
         public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
             if (o instanceof MarkerAttribute) {
                 MarkerAttribute attr = (MarkerAttribute) o;
                 return ((attr.namespace == this.namespace)
Index: java/org/apache/fop/fo/flow/table/TableColumn.java
===================================================================
--- java/org/apache/fop/fo/flow/table/TableColumn.java	(revision 723701)
+++ java/org/apache/fop/fo/flow/table/TableColumn.java	(working copy)
@@ -230,7 +230,9 @@
             sb.append(" number-columns-spanned=")
                 .append(getNumberColumnsSpanned());
         }
-        sb.append(" column-width=").append(getColumnWidth());
+        //sb.append(" column-width=").append(getColumnWidth());
+        // bug fixation
+        sb.append(" column-width=").append(((Property)getColumnWidth()).getString());
         return sb.toString();
     }
 
Index: java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java
===================================================================
--- java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java	(working copy)
@@ -41,7 +41,11 @@
      */
     public static class Maker extends ListProperty.Maker {
 
-        /** {@inheritDoc} */
+        /**
+         * Construct an instance of a Maker for the given property.
+         * 
+         * @param propId The Constant ID of the property to be made.
+         */
         public Maker(int propId) {
             super(propId);
         }
@@ -72,7 +76,7 @@
          * Returns a {@link org.apache.fop.datatypes.PercentBase} whose
          * <code>getDimension()</code> returns 1.
          */
-        public PercentBase getPercentBase() {
+        public PercentBase getPercentBase(PropertyList pl) {
             return new PercentBase() {
                 /** {@inheritDoc} */
                 public int getBaseLength(PercentBaseContext context) throws PropertyException {
Index: java/org/apache/fop/fo/properties/CharacterProperty.java
===================================================================
--- java/org/apache/fop/fo/properties/CharacterProperty.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/CharacterProperty.java	(working copy)
@@ -48,7 +48,7 @@
     }
 
     /** cache containing all canonical CharacterProperty instances */
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(CharacterProperty.class);
 
     private final char character;
 
Index: java/org/apache/fop/fo/properties/ColorProperty.java
===================================================================
--- java/org/apache/fop/fo/properties/ColorProperty.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/ColorProperty.java	(working copy)
@@ -33,7 +33,7 @@
 public final class ColorProperty extends Property  {
     
     /** cache holding canonical ColorProperty instances */
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(ColorProperty.class);
     
     /**
      * The color represented by this property.
@@ -92,6 +92,8 @@
      * 
      * @param foUserAgent FOP user agent
      * @param value RGB value as String to be parsed
+     * @return the canonical ColorProperty instance corresponding 
+     *         to the given value
      * @throws PropertyException if the value can't be parsed
      * @see ColorUtil#parseColorString(FOUserAgent, String)
      */
@@ -99,19 +101,10 @@
         ColorProperty instance = new ColorProperty(
                                        ColorUtil.parseColorString(
                                                foUserAgent, value));
-        return (ColorProperty) cache.fetch(instance);
+        return (ColorProperty)cache.fetch(instance);
     }
 
     /**
-     * Returns an instance of a color property given a color
-     * @param color the color value
-     * @return the color property
-     */
-    public static ColorProperty getInstance(Color color) {
-        return (ColorProperty) cache.fetch(new ColorProperty(color));
-    }
-    
-    /**
      * Create a new ColorProperty with a given color.
      * 
      * @param value the color to use.
Index: java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
===================================================================
--- java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java	(working copy)
@@ -38,35 +38,44 @@
  * See Sec. 7.7 of the XSL-FO Standard.
  */
 public class CommonBorderPaddingBackground {
+
+    /** 
+     *  cache holding all canonical instances 
+     *  (w/ absolute background-position-* and padding-*)
+     */
+    private static final PropertyCache cache = new PropertyCache(CommonBorderPaddingBackground.class);
+    
+    private int hash = -1;
+    
     /**
      * The "background-attachment" property.
      */
-    public int backgroundAttachment;
+    public final int backgroundAttachment;
 
     /**
      * The "background-color" property.
      */
-    public Color backgroundColor;
+    public final Color backgroundColor;
 
     /**
      * The "background-image" property.
      */
-    public String backgroundImage;
+    public final String backgroundImage;
 
     /**
      * The "background-repeat" property.
      */
-    public int backgroundRepeat;
+    public final int backgroundRepeat;
 
     /**
      * The "background-position-horizontal" property.
      */
-    public Length backgroundPositionHorizontal;
+    public final Length backgroundPositionHorizontal;
 
     /**
      * The "background-position-vertical" property.
      */
-    public Length backgroundPositionVertical;
+    public final Length backgroundPositionVertical;
 
 
     private ImageInfo backgroundImageInfo;
@@ -81,29 +90,68 @@
     /** the "end" edge */
     public static final int END = 3;
 
+    /**
+     * 
+     */
     public static class BorderInfo {
+        
+        /** cache holding all canonical instances */
+        private static final PropertyCache cache = new PropertyCache(BorderInfo.class);
+        
         private int mStyle; // Enum for border style
         private Color mColor; // Border color
         private CondLengthProperty mWidth;
+        
+        private int hash = -1;
 
-        BorderInfo(int style, CondLengthProperty width, Color color) {
+        /**
+         * Hidden constructor
+         */
+        private BorderInfo(int style, CondLengthProperty width, Color color) {
             mStyle = style;
             mWidth = width;
             mColor = color;
         }
 
+        /**
+         * Returns a BorderInfo instance corresponding to the given values
+         * 
+         * @param style the border-style
+         * @param width the border-width
+         * @param color the border-color
+         * @return a cached BorderInfo instance
+         */
+        public static BorderInfo getInstance(int style, CondLengthProperty width, Color color) {
+            return cache.fetch(new BorderInfo(style, width, color));
+        }
+
+        /**
+         * @return  the border-style
+         */
         public int getStyle() {
             return this.mStyle;
         }
 
+        /**
+         * @return the border-color
+         */
         public Color getColor() {
             return this.mColor;
         }
 
+        /**
+         * @return the border-width
+         */
         public CondLengthProperty getWidth() {
             return this.mWidth;
         }
 
+        /**
+         * Convenience method returning the border-width,
+         * taking into account values of "none" and "hidden"
+         * 
+         * @return  the retained border-width
+         */
         public int getRetainedWidth() {
             if ((mStyle == Constants.EN_NONE)
                     || (mStyle == Constants.EN_HIDDEN)) {
@@ -125,14 +173,43 @@
             sb.append("}");
             return sb.toString();
         }
+        
+        /** {@inheritDoc} */
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            
+            if (obj instanceof BorderInfo) {
+                BorderInfo bi = (BorderInfo)obj;
+                return (this.mColor == bi.mColor
+                    && this.mStyle == bi.mStyle
+                    && this.mWidth == bi.mWidth);
+            }
+            
+            return false;
+        }
+        
+        /** {@inheritDoc} */
+        public int hashCode() {
+            if (this.hash == -1) {
+                int hash = 17;
+                hash = 37 * hash + (mColor == null ? 0 : mColor.hashCode());
+                hash = 37 * hash + mStyle;
+                hash = 37 * hash + (mWidth == null ? 0 : mWidth.hashCode());
+                this.hash = hash;
+            }
+            return this.hash;
+        }
     }
 
     /**
-     * A border info with style none. Used as a singleton, in the collapsing-border model,
+     * A border info with style "none". Used as a singleton, in the collapsing-border model,
      * for elements which don't specify any border on some of their sides.
      */
-    private static BorderInfo defaultBorderInfo;
-
+    private static final BorderInfo defaultBorderInfo 
+            = BorderInfo.getInstance(Constants.EN_NONE, new ConditionalNullLength(), null);
+    
     /**
      * A conditional length of value 0. Returned by the
      * {@link CommonBorderPaddingBackground#getBorderInfo(int)} method when the
@@ -191,12 +268,7 @@
      * 
      * @return a BorderInfo instance with style set to {@link Constants#EN_NONE}
      */
-    public static synchronized BorderInfo getDefaultBorderInfo() {
-        if (defaultBorderInfo == null) {
-            /* It is enough to set color to null, as it should never be consulted */
-            defaultBorderInfo = new BorderInfo(Constants.EN_NONE,
-                    new ConditionalNullLength(), null);
-        }
+    public static BorderInfo getDefaultBorderInfo() {
         return defaultBorderInfo;
     }
 
@@ -205,29 +277,30 @@
 
     /**
      * Construct a CommonBorderPaddingBackground object.
-     */
-    public CommonBorderPaddingBackground() {
-    }
-
-    /**
-     * Construct a CommonBorderPaddingBackground object.
      * 
      * @param pList The PropertyList to get properties from.
      * @throws PropertyException if there's an error while binding the properties
      */
-    public CommonBorderPaddingBackground(PropertyList pList) throws PropertyException {
+    private CommonBorderPaddingBackground(PropertyList pList) throws PropertyException {
 
         backgroundAttachment = pList.get(Constants.PR_BACKGROUND_ATTACHMENT).getEnum();
-        backgroundColor = pList.get(Constants.PR_BACKGROUND_COLOR).getColor(
+        
+        Color bc = pList.get(Constants.PR_BACKGROUND_COLOR).getColor(
                                         pList.getFObj().getUserAgent());
-        if (backgroundColor.getAlpha() == 0) {
+        if (bc.getAlpha() == 0) {
             backgroundColor = null;
+        } else {
+            backgroundColor = bc;
         }
 
-        backgroundImage = pList.get(Constants.PR_BACKGROUND_IMAGE).getString();
-        if (backgroundImage == null || "none".equals(backgroundImage)) {
-            backgroundImage = null;
+        String img = pList.get(Constants.PR_BACKGROUND_IMAGE).getString();
+        if (img == null || "none".equals(img)) {
+            backgroundImage = "";
+            backgroundRepeat = -1;
+            backgroundPositionHorizontal = null;
+            backgroundPositionVertical = null;
         } else {
+            backgroundImage = img;
             backgroundRepeat = pList.get(Constants.PR_BACKGROUND_REPEAT).getEnum();
             backgroundPositionHorizontal = pList.get(
                     Constants.PR_BACKGROUND_POSITION_HORIZONTAL).getLength();
@@ -272,18 +345,48 @@
 
     }
 
+    /**
+     * Obtain a CommonBorderPaddingBackground instance based on the 
+     * related property valus in the given {@link PropertyList}
+     * 
+     * @param pList the {@link PropertyList} to use
+     * @return a CommonBorderPaddingBackground instance (cached if possible)
+     * @throws PropertyException in case of an error
+     */
+    public static CommonBorderPaddingBackground getInstance(PropertyList pList) 
+        throws PropertyException {
+        
+        CommonBorderPaddingBackground newInstance
+                = new CommonBorderPaddingBackground(pList);
+        
+        /* if padding-* and background-position-* resolve to absolute lengths
+         * the whole instance can be cached */
+        if ((newInstance.padding[BEFORE] == null || newInstance.padding[BEFORE].getLength().isAbsolute())
+                && (newInstance.padding[AFTER] == null || newInstance.padding[AFTER].getLength().isAbsolute())
+                && (newInstance.padding[START] == null || newInstance.padding[START].getLength().isAbsolute())
+                && (newInstance.padding[END] == null || newInstance.padding[END].getLength().isAbsolute())
+                && (newInstance.backgroundPositionHorizontal == null || newInstance.backgroundPositionHorizontal.isAbsolute())
+                && (newInstance.backgroundPositionVertical == null || newInstance.backgroundPositionVertical.isAbsolute())) {
+            return cache.fetch(newInstance);
+        }
+        
+        return newInstance;
+    }
+
     private void initBorderInfo(PropertyList pList, int side,
                     int colorProp, int styleProp, int widthProp, int paddingProp)
                 throws PropertyException {
+        
         padding[side] = pList.get(paddingProp).getCondLength();
         // If style = none, force width to 0, don't get Color (spec 7.7.20)
         int style = pList.get(styleProp).getEnum();
         if (style != Constants.EN_NONE) {
             FOUserAgent ua = pList.getFObj().getUserAgent();
-            setBorderInfo(new BorderInfo(style,
+            setBorderInfo(BorderInfo.getInstance(style,
                 pList.get(widthProp).getCondLength(),
                 pList.get(colorProp).getColor(ua)), side);
         }
+        
     }
 
     /**
@@ -291,7 +394,7 @@
      * @param info the border information
      * @param side the side to apply the info to
      */
-    public void setBorderInfo(BorderInfo info, int side) {
+    private void setBorderInfo(BorderInfo info, int side) {
         this.borderInfo[side] = info;
     }
 
@@ -308,14 +411,6 @@
     }
 
     /**
-     * Set padding.
-     * @param source the padding info to copy from
-     */
-    public void setPadding(CommonBorderPaddingBackground source) {
-        this.padding = source.padding;
-    }
-
-    /**
      * @return the background image info object, null if there is
      *     no background image.
      */
@@ -324,64 +419,102 @@
     }
 
     /**
-     * @param bDiscard indicates whether the .conditionality component should be
+     * @param discard indicates whether the .conditionality component should be
      * considered (start of a reference-area)
+     * @return the width of the start-border, taking into account the specified conditionality
      */
-    public int getBorderStartWidth(boolean bDiscard) {
-        return getBorderWidth(START, bDiscard);
+    public int getBorderStartWidth(boolean discard) {
+        return getBorderWidth(START, discard);
     }
 
     /**
-     * @param bDiscard indicates whether the .conditionality component should be
+     * @param discard indicates whether the .conditionality component should be
      * considered (end of a reference-area)
+     * @return the width of the end-border, taking into account the specified conditionality
      */
-    public int getBorderEndWidth(boolean bDiscard) {
-        return getBorderWidth(END, bDiscard);
+    public int getBorderEndWidth(boolean discard) {
+        return getBorderWidth(END, discard);
     }
 
     /**
-     * @param bDiscard indicates whether the .conditionality component should be
+     * @param discard indicates whether the .conditionality component should be
      * considered (start of a reference-area)
+     * @return the width of the before-border, taking into account the specified conditionality
      */
-    public int getBorderBeforeWidth(boolean bDiscard) {
-        return getBorderWidth(BEFORE, bDiscard);
+    public int getBorderBeforeWidth(boolean discard) {
+        return getBorderWidth(BEFORE, discard);
     }
 
     /**
-     * @param bDiscard indicates whether the .conditionality component should be
+     * @param discard indicates whether the .conditionality component should be
      * considered (end of a reference-area)
+     * @return the width of the after-border, taking into account the specified conditionality
      */
-    public int getBorderAfterWidth(boolean bDiscard) {
-        return getBorderWidth(AFTER, bDiscard);
+    public int getBorderAfterWidth(boolean discard) {
+        return getBorderWidth(AFTER, discard);
     }
 
-    public int getPaddingStart(boolean bDiscard, PercentBaseContext context) {
-        return getPadding(START, bDiscard, context);
+    /**
+     * @param discard indicates whether the .conditionality component should be
+     * considered (start of a reference-area)
+     * @param context the context to evaluate percentage values
+     * @return the width of the start-padding, taking into account the specified conditionality
+     */
+    public int getPaddingStart(boolean discard, PercentBaseContext context) {
+        return getPadding(START, discard, context);
     }
 
-    public int getPaddingEnd(boolean bDiscard, PercentBaseContext context) {
-        return getPadding(END, bDiscard, context);
+    /**
+     * @param discard indicates whether the .conditionality component should be
+     * considered (start of a reference-area)
+     * @param context the context to evaluate percentage values
+     * @return the width of the end-padding, taking into account the specified conditionality
+     */
+    public int getPaddingEnd(boolean discard, PercentBaseContext context) {
+        return getPadding(END, discard, context);
     }
 
-    public int getPaddingBefore(boolean bDiscard, PercentBaseContext context) {
-        return getPadding(BEFORE, bDiscard, context);
+    /**
+     * @param discard indicates whether the .conditionality component should be
+     * considered (start of a reference-area)
+     * @param context the context to evaluate percentage values
+     * @return the width of the before-padding, taking into account the specified conditionality
+     */
+    public int getPaddingBefore(boolean discard, PercentBaseContext context) {
+        return getPadding(BEFORE, discard, context);
     }
 
-    public int getPaddingAfter(boolean bDiscard, PercentBaseContext context) {
-        return getPadding(AFTER, bDiscard, context);
+    /**
+     * @param discard indicates whether the .conditionality component should be
+     * considered (start of a reference-area)
+     * @param context the context to evaluate percentage values
+     * @return the width of the after-padding, taking into account the specified conditionality
+     */
+    public int getPaddingAfter(boolean discard, PercentBaseContext context) {
+        return getPadding(AFTER, discard, context);
     }
 
-    public int getBorderWidth(int side, boolean bDiscard) {
+    /**
+     * @param discard indicates whether the .conditionality component should be
+     * considered (end of a reference-area)
+     * @return the width of the start-border, taking into account the specified conditionality
+     */
+    public int getBorderWidth(int side, boolean discard) {
         if ((borderInfo[side] == null)
                 || (borderInfo[side].mStyle == Constants.EN_NONE)
                 || (borderInfo[side].mStyle == Constants.EN_HIDDEN)
-                || (bDiscard && borderInfo[side].mWidth.isDiscard())) {
+                || (discard && borderInfo[side].mWidth.isDiscard())) {
             return 0;
         } else {
             return borderInfo[side].mWidth.getLengthValue();
         }
     }
 
+    /**
+     * 
+     * @param side
+     * @return
+     */
     public Color getBorderColor(int side) {
         if (borderInfo[side] != null) {
             return borderInfo[side].getColor();
@@ -390,6 +523,11 @@
         }
     }
 
+    /**
+     * 
+     * @param side
+     * @return
+     */
     public int getBorderStyle(int side) {
         if (borderInfo[side] != null) {
             return borderInfo[side].mStyle;
@@ -398,8 +536,15 @@
         }
     }
 
-    public int getPadding(int side, boolean bDiscard, PercentBaseContext context) {
-        if ((padding[side] == null) || (bDiscard && padding[side].isDiscard())) {
+    /**
+     * 
+     * @param side
+     * @param discard
+     * @param context
+     * @return
+     */
+    public int getPadding(int side, boolean discard, PercentBaseContext context) {
+        if ((padding[side] == null) || (discard && padding[side].isDiscard())) {
             return 0;
         } else {
             return padding[side].getLengthValue(context);
@@ -418,27 +563,27 @@
     /**
      * Return all the border and padding width in the inline progression
      * dimension.
-     * @param bDiscard the discard flag.
+     * @param discard the discard flag.
      * @param context for percentage evaluation.
      * @return all the padding and border width.
      */
-    public int getIPPaddingAndBorder(boolean bDiscard, PercentBaseContext context) {
-        return getPaddingStart(bDiscard, context)
-            + getPaddingEnd(bDiscard, context)
-            + getBorderStartWidth(bDiscard)
-            + getBorderEndWidth(bDiscard);
+    public int getIPPaddingAndBorder(boolean discard, PercentBaseContext context) {
+        return getPaddingStart(discard, context)
+            + getPaddingEnd(discard, context)
+            + getBorderStartWidth(discard)
+            + getBorderEndWidth(discard);
     }
 
     /**
      * Return all the border and padding height in the block progression
      * dimension.
-     * @param bDiscard the discard flag.
+     * @param discard the discard flag.
      * @param context for percentage evaluation
      * @return all the padding and border height.
      */
-    public int getBPPaddingAndBorder(boolean bDiscard, PercentBaseContext context) {
-        return getPaddingBefore(bDiscard, context) + getPaddingAfter(bDiscard, context)
-               + getBorderBeforeWidth(bDiscard) + getBorderAfterWidth(bDiscard);
+    public int getBPPaddingAndBorder(boolean discard, PercentBaseContext context) {
+        return getPaddingBefore(discard, context) + getPaddingAfter(discard, context)
+               + getBorderBeforeWidth(discard) + getBorderAfterWidth(discard);
     }
 
     /** {@inheritDoc} */
@@ -479,4 +624,54 @@
         return (borderInfo[BEFORE] != null || borderInfo[AFTER] != null
                 || borderInfo[START] != null || borderInfo[END] != null);
     }
+    
+    /** {@inheritDoc} */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof CommonBorderPaddingBackground) {
+            CommonBorderPaddingBackground cbpb = (CommonBorderPaddingBackground)obj;
+            return (this.backgroundAttachment == cbpb.backgroundAttachment
+                && this.backgroundColor == cbpb.backgroundColor
+                && this.backgroundImage.equals(cbpb.backgroundImage)
+                && this.backgroundPositionHorizontal == cbpb.backgroundPositionHorizontal
+                && this.backgroundPositionVertical == cbpb.backgroundPositionVertical
+                && this.backgroundRepeat == cbpb.backgroundRepeat
+                && this.borderInfo[BEFORE] == cbpb.borderInfo[BEFORE]
+                && this.borderInfo[AFTER] == cbpb.borderInfo[AFTER]
+                && this.borderInfo[START] == cbpb.borderInfo[START]
+                && this.borderInfo[END] == cbpb.borderInfo[END]
+                && this.padding[BEFORE] == cbpb.padding[BEFORE]
+                && this.padding[AFTER] == cbpb.padding[AFTER]
+                && this.padding[START] == cbpb.padding[START]
+                && this.padding[END] == cbpb.padding[END]);
+        }
+        
+        return false;
+    }
+    
+    /** {@inheritDoc} */
+    public int hashCode() {
+        if (this.hash == -1) {
+            int hash = 17;
+            hash = 37 * hash + backgroundAttachment;
+            hash = 37 * hash + (backgroundColor == null ? 0 : backgroundColor.hashCode());
+            hash = 37 * hash + (backgroundImage == null ? 0 : backgroundImage.hashCode());
+            hash = 37 * hash + (backgroundPositionHorizontal == null ? 0 : backgroundPositionHorizontal.hashCode());
+            hash = 37 * hash + (backgroundPositionVertical == null ? 0 : backgroundPositionVertical.hashCode());
+            hash = 37 * hash + backgroundRepeat;
+            hash = 37 * hash + (borderInfo[BEFORE] == null ? 0 : borderInfo[BEFORE].hashCode());
+            hash = 37 * hash + (borderInfo[AFTER] == null ? 0 : borderInfo[AFTER].hashCode());
+            hash = 37 * hash + (borderInfo[START] == null ? 0 : borderInfo[START].hashCode());
+            hash = 37 * hash + (borderInfo[END] == null ? 0 : borderInfo[END].hashCode());
+            hash = 37 * hash + (padding[BEFORE] == null ? 0 : padding[BEFORE].hashCode());
+            hash = 37 * hash + (padding[AFTER] == null ? 0 : padding[AFTER].hashCode());
+            hash = 37 * hash + (padding[START] == null ? 0 : padding[START].hashCode());
+            hash = 37 * hash + (padding[END] == null ? 0 : padding[END].hashCode());
+            this.hash = hash;
+        }
+        
+        return this.hash;
+    }
 }
Index: java/org/apache/fop/fo/properties/CommonFont.java
===================================================================
--- java/org/apache/fop/fo/properties/CommonFont.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/CommonFont.java	(working copy)
@@ -37,179 +37,62 @@
 
     /** cache holding canonical CommonFont instances (only those with
      *  absolute font-size and font-size-adjust) */
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(CommonFont.class);
     
-    /**
-     * Class holding canonical instances of bundles of the
-     * cacheable (non-relative) CommonFont properties
-     *
-     */
-    protected static final class CachedCommonFont {
-        
-        /** cache holding all canonical instances */
-        private static final PropertyCache cache = new PropertyCache();
-        
-        private int hash = 0;
-        
-        /**
-         * The "font-family" property.
-         */
-        private final FontFamilyProperty fontFamily;
+    /** hashcode of this instance */
+    private int hash = 0;
     
-        /**
-         * The "font-selection-strategy" property.
-         */
-        private final EnumProperty fontSelectionStrategy;
-    
-        /**
-         * The "font-stretch" property.
-         */
-        private final EnumProperty fontStretch;
+    /** The "font-family" property. */
+    private final FontFamilyProperty fontFamily;
 
-        /**
-         * The "font-style" property.
-         */
-        private final EnumProperty fontStyle;
+    /** The "font-selection-strategy" property. */
+    private final EnumProperty fontSelectionStrategy;
 
-        /**
-         * The "font-variant" property.
-         */
-        private final EnumProperty fontVariant;
+    /** The "font-stretch" property. */
+    private final EnumProperty fontStretch;
 
-        /**
-         * The "font-weight" property.
-         */
-        private final EnumProperty fontWeight;
-        
-        /**
-         * Constructor
-         * 
-         * @param fontFamily    the font-family property
-         * @param fontSelectionStrategy the font-selection-strategy property
-         * @param fontStretch   the font-stretch property
-         * @param fontStyle     the font-style property
-         * @param fontVariant   the font-variant property
-         * @param fontWeight    the font-weight property
-         */
-        private CachedCommonFont(FontFamilyProperty fontFamily,
-                         EnumProperty fontSelectionStrategy,
-                         EnumProperty fontStretch,
-                         EnumProperty fontStyle,
-                         EnumProperty fontVariant,
-                         EnumProperty fontWeight) {
-            this.fontFamily = fontFamily;
-            this.fontSelectionStrategy = fontSelectionStrategy;
-            this.fontStretch = fontStretch;
-            this.fontStyle = fontStyle;
-            this.fontVariant = fontVariant;
-            this.fontWeight = fontWeight;
-        }
-        
-        /**
-         * Returns the canonical instance corresponding to the given
-         * properties
-         * 
-         * @param fontFamily    the font-family property
-         * @param fontSelectionStrategy the font-selection-strategy property
-         * @param fontStretch   the font-stretch property
-         * @param fontStyle     the font-style property
-         * @param fontVariant   the font-variant property
-         * @param fontWeight    the font-weight property
-         * @return  the canonical instance
-         */
-        private static final CachedCommonFont getInstance(FontFamilyProperty fontFamily,
-                           EnumProperty fontSelectionStrategy,
-                           EnumProperty fontStretch,
-                           EnumProperty fontStyle,
-                           EnumProperty fontVariant,
-                           EnumProperty fontWeight) {
-            return cache.fetch(new CachedCommonFont(
-                                    fontFamily,
-                                    fontSelectionStrategy,
-                                    fontStretch,
-                                    fontStyle,
-                                    fontVariant,
-                                    fontWeight));
-        }
-        
-        /** @return the first font-family name in the list */
-        private String getFirstFontFamily() {
-            return ((Property) fontFamily.list.get(0)).getString();
-        }
-        
-        /** @return an array with the font-family names */
-        private String[] getFontFamily() {
-            List lst = fontFamily.getList();
-            String[] fontFamily = new String[lst.size()];
-            for (int i = 0, c = lst.size(); i < c; i++) {
-                fontFamily[i] = ((Property)lst.get(i)).getString();
-            }
-            return fontFamily;
-        }
-        
-        /** {@inheritDoc} */
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            
-            if (o instanceof CachedCommonFont) {
-                CachedCommonFont ccf = (CachedCommonFont) o;
-                return (ccf.fontFamily == this.fontFamily)
-                    && (ccf.fontSelectionStrategy == this.fontSelectionStrategy)
-                    && (ccf.fontStretch == this.fontStretch)
-                    && (ccf.fontStyle == this.fontStyle)
-                    && (ccf.fontVariant == this.fontVariant)
-                    && (ccf.fontWeight == this.fontWeight);
-            }
-            return false;
-        }
-        
-        /** {@inheritDoc} */
-        public int hashCode() {
-            if (this.hash == 0) {
-                int hash = 17;
-                hash = 37 * hash + (fontFamily == null ? 0 : fontFamily.hashCode());
-                hash = 37 * hash + (fontSelectionStrategy == null ? 0 : fontSelectionStrategy.hashCode());
-                hash = 37 * hash + (fontStretch == null ? 0 : fontStretch.hashCode());
-                hash = 37 * hash + (fontStyle == null ? 0 : fontStyle.hashCode());
-                hash = 37 * hash + (fontVariant == null ? 0 : fontVariant.hashCode());
-                hash = 37 * hash + (fontStretch == null ? 0 : fontStretch.hashCode());
-                this.hash = hash;
-            }
-            return this.hash;
-        }
-        
-    }
+    /** The "font-style" property. */
+    private final EnumProperty fontStyle;
 
-    /**
-     * The cached CommonFont properties (access these through the getters)
-     * The remaining properties, font-size and font-size-adjust,
-     * will only be cached values if they are absolute.
-     */
-    private final CachedCommonFont cachedCommonFont;
+    /** The "font-variant" property. */
+    private final EnumProperty fontVariant;
+
+    /** The "font-weight" property. */
+    private final EnumProperty fontWeight;
     
-    /**
-     * The "font-size" property.
-     */
+    /** The "font-size" property. */
     public final Length fontSize;
 
-    /**
-     * The "font-size-adjust" property.
-     */
+    /** The "font-size-adjust" property. */
     public final Numeric fontSizeAdjust;
 
+    
     /**
      * Construct a CommonFont instance
      * 
-     * @param ccf       the cached CommonFont properties
+     * @param fontFamily    the font-family property
+     * @param fontSelectionStrategy the font-selection-strategy property
+     * @param fontStretch   the font-stretch property
+     * @param fontStyle     the font-style property
+     * @param fontVariant   the font-variant property
+     * @param fontWeight    the font-weight property
      * @param fontSize  the font-size (possibly non-cached)
      * @param fontSizeAdjust    the font-size-adjust (possibly non-cached)
      */
-    private CommonFont(CachedCommonFont ccf, 
+    private CommonFont(FontFamilyProperty fontFamily,
+                       EnumProperty fontSelectionStrategy,
+                       EnumProperty fontStretch,
+                       EnumProperty fontStyle,
+                       EnumProperty fontVariant,
+                       EnumProperty fontWeight, 
                        Length fontSize, 
                        Numeric fontSizeAdjust) {
-        this.cachedCommonFont = ccf;
+        this.fontFamily = fontFamily;
+        this.fontSelectionStrategy = fontSelectionStrategy;
+        this.fontStretch = fontStretch;
+        this.fontStyle = fontStyle;
+        this.fontVariant = fontVariant;
+        this.fontWeight = fontWeight;
         this.fontSize = fontSize;
         this.fontSizeAdjust = fontSizeAdjust;
     }
@@ -232,53 +115,59 @@
         EnumProperty fontStyle = (EnumProperty) pList.get(Constants.PR_FONT_STYLE);
         EnumProperty fontVariant = (EnumProperty) pList.get(Constants.PR_FONT_VARIANT);
         EnumProperty fontWeight = (EnumProperty) pList.get(Constants.PR_FONT_WEIGHT);
-        CachedCommonFont cachedCommonFont = CachedCommonFont.getInstance(
-                                                fontFamily, 
-                                                fontSelectionStrategy, 
-                                                fontStretch, 
-                                                fontStyle, 
-                                                fontVariant, 
-                                                fontWeight);
-        
         Numeric fontSizeAdjust = pList.get(Constants.PR_FONT_SIZE_ADJUST).getNumeric();
         Length fontSize = pList.get(Constants.PR_FONT_SIZE).getLength();
-        CommonFont cf = new CommonFont(cachedCommonFont, fontSize, fontSizeAdjust);
-        if (fontSize.isAbsolute() && fontSizeAdjust.isAbsolute()) {
-            return cache.fetch(cf);
-        } else {
-            return cf;
-        }
         
+        CommonFont commonFont = new CommonFont(fontFamily, 
+                                               fontSelectionStrategy, 
+                                               fontStretch, 
+                                               fontStyle, 
+                                               fontVariant, 
+                                               fontWeight,
+                                               fontSize,
+                                               fontSizeAdjust);
+        
+        return cache.fetch(commonFont);
     }
     
+    /** @return an array with the font-family names */
+    private String[] getFontFamily() {
+        List lst = fontFamily.getList();
+        String[] fontFamily = new String[lst.size()];
+        for (int i = 0, c = lst.size(); i < c; i++) {
+            fontFamily[i] = ((Property)lst.get(i)).getString();
+        }
+        return fontFamily;
+    }
+        
     /** @return the first font-family name in the list */
     public String getFirstFontFamily() {
-        return cachedCommonFont.getFirstFontFamily();
+        return ((Property) fontFamily.list.get(0)).getString();
     }
     
     /** @return the "font-selection-strategy" property */
     public int getFontSelectionStrategy() {
-        return cachedCommonFont.fontSelectionStrategy.getEnum();
+        return fontSelectionStrategy.getEnum();
     }
 
     /** @return the "font-stretch" property */
     public int getFontStretch() {
-        return cachedCommonFont.fontStretch.getEnum();
+        return fontStretch.getEnum();
     }
     
     /** @return the "font-style" property */
     public int getFontStyle() {
-        return cachedCommonFont.fontStyle.getEnum();
+        return fontStyle.getEnum();
     }
     
     /** @return the "font-variant" property */
     public int getFontVariant() {
-        return cachedCommonFont.fontVariant.getEnum();
+        return fontVariant.getEnum();
     }
 
     /** @return the "font-weight" property */
     public int getFontWeight() {
-        return cachedCommonFont.fontWeight.getEnum();
+        return fontWeight.getEnum();
     }
     
     /**
@@ -290,7 +179,7 @@
      */
     public FontTriplet[] getFontState(FontInfo fontInfo) {
         int font_weight;
-        switch (cachedCommonFont.fontWeight.getEnum()) {
+        switch (fontWeight.getEnum()) {
         case Constants.EN_100: font_weight = 100; break;
         case Constants.EN_200: font_weight = 200; break;
         case Constants.EN_300: font_weight = 300; break;
@@ -304,7 +193,7 @@
         }
 
         String style;
-        switch (cachedCommonFont.fontStyle.getEnum()) {
+        switch (fontStyle.getEnum()) {
         case Constants.EN_ITALIC: 
             style = "italic";
             break;
@@ -321,32 +210,53 @@
         // various kinds of keywords too
         //int fontVariant = propertyList.get("font-variant").getEnum();
         FontTriplet[] triplets = fontInfo.fontLookup(
-                                    cachedCommonFont.getFontFamily(), 
+                                    getFontFamily(), 
                                     style, font_weight);
         return triplets;
     }
 
     /** {@inheritDoc} */
     public boolean equals(Object o) {
+        
+        if (o == null) {
+            return false;
+        }
+        
         if (this == o) {
             return true;
         }
         
         if (o instanceof CommonFont) {
             CommonFont cf = (CommonFont) o;
-            return (cf.cachedCommonFont == this.cachedCommonFont
-                    && cf.fontSize == this.fontSize
-                    && cf.fontSizeAdjust == this.fontSizeAdjust);
+            return (cf.fontFamily == this.fontFamily)
+                    && (cf.fontSelectionStrategy == this.fontSelectionStrategy)
+                    && (cf.fontStretch == this.fontStretch)
+                    && (cf.fontStyle == this.fontStyle)
+                    && (cf.fontVariant == this.fontVariant)
+                    && (cf.fontWeight == this.fontWeight)
+                    && (cf.fontSize == this.fontSize)
+                    && (cf.fontSizeAdjust == this.fontSizeAdjust);
         }
         return false;
+        
     }
     
     /** {@inheritDoc} */
     public int hashCode() {
-        int hash = 17;
-        hash = 37 * hash + cachedCommonFont.hashCode();
-        hash = 37 * hash + fontSize.hashCode();
-        hash = 37 * hash + fontSizeAdjust.hashCode();
+        
+        if (this.hash == -1) {
+            int hash = 17;
+            hash = 37 * hash + (fontSize == null ? 0 : fontSize.hashCode());
+            hash = 37 * hash + (fontSizeAdjust == null ? 0 : fontSizeAdjust.hashCode());
+            hash = 37 * hash + (fontFamily == null ? 0 : fontFamily.hashCode());
+            hash = 37 * hash + (fontSelectionStrategy == null ? 0 : fontSelectionStrategy.hashCode());
+            hash = 37 * hash + (fontStretch == null ? 0 : fontStretch.hashCode());
+            hash = 37 * hash + (fontStyle == null ? 0 : fontStyle.hashCode());
+            hash = 37 * hash + (fontVariant == null ? 0 : fontVariant.hashCode());
+            hash = 37 * hash + (fontStretch == null ? 0 : fontStretch.hashCode());
+            this.hash = hash;
+        }
         return hash;
+        
     }
 }
Index: java/org/apache/fop/fo/properties/CommonHyphenation.java
===================================================================
--- java/org/apache/fop/fo/properties/CommonHyphenation.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/CommonHyphenation.java	(working copy)
@@ -37,7 +37,7 @@
     /** Logger */
     protected static Log log = LogFactory.getLog(CommonHyphenation.class);
     
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(CommonHyphenation.class);
     
     private int hash = 0;
     
Index: java/org/apache/fop/fo/properties/CondLengthProperty.java
===================================================================
--- java/org/apache/fop/fo/properties/CondLengthProperty.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/CondLengthProperty.java	(working copy)
@@ -31,8 +31,16 @@
  * Superclass for properties that have conditional lengths
  */
 public class CondLengthProperty extends Property implements CompoundDatatype {
+    
+    /** cache holding canonical instances (for absolute conditional lengths) */
+    private static final PropertyCache cache = new PropertyCache(CondLengthProperty.class);
+    
+    /** components */
     private Property length;
     private EnumProperty conditionality;
+    
+    private boolean isCached = false;
+    private int hash = -1;
 
     /**
      * Inner class for creating instances of CondLengthProperty
@@ -71,6 +79,11 @@
      */
     public void setComponent(int cmpId, Property cmpnValue,
                              boolean bIsDefault) {
+        if (isCached) {
+            throw new IllegalStateException(
+                    "CondLengthProperty.setComponent() called on a cached value!");
+        }
+        
         if (cmpId == CP_LENGTH) {
             length = cmpnValue;
         } else if (cmpId == CP_CONDITIONALITY) {
@@ -144,7 +157,15 @@
      * @return this.condLength
      */
     public CondLengthProperty getCondLength() {
-        return this;
+        if (this.length.getLength().isAbsolute()) {
+            CondLengthProperty clp = (CondLengthProperty) cache.fetch(this);
+            if (clp == this) {
+                isCached = true;
+            }
+            return clp;
+        } else {
+            return this;
+        }
     }
 
     /**
@@ -162,4 +183,28 @@
         return this;
     }
 
+    /** {@inheritDoc} */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        
+        if (obj instanceof CondLengthProperty) {
+            CondLengthProperty clp = (CondLengthProperty)obj;
+            return (this.length == clp.length
+                    && this.conditionality == clp.conditionality);
+        }
+        return false;
+    }
+    
+    /** {@inheritDoc} */
+    public int hashCode() {
+        if (this.hash == -1) {
+            int hash = 17;
+            hash = 37 * hash + (length == null ? 0 : length.hashCode());
+            hash = 37 * hash + (conditionality == null ? 0 : conditionality.hashCode());
+            this.hash = hash;
+        }
+        return this.hash;
+    }
 }
Index: java/org/apache/fop/fo/properties/EnumNumber.java
===================================================================
--- java/org/apache/fop/fo/properties/EnumNumber.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/EnumNumber.java	(working copy)
@@ -29,7 +29,7 @@
 public final class EnumNumber extends Property implements Numeric {
 
     /** cache holding all canonical EnumNumber instances */
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(EnumNumber.class);
 
     private final EnumProperty enumProperty;
     
Index: java/org/apache/fop/fo/properties/EnumProperty.java
===================================================================
--- java/org/apache/fop/fo/properties/EnumProperty.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/EnumProperty.java	(working copy)
@@ -29,7 +29,7 @@
 public final class EnumProperty extends Property {
     
     /** cache holding all canonical EnumProperty instances */
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(EnumProperty.class);
 
     /**
      * Inner class for creating EnumProperty instances
Index: java/org/apache/fop/fo/properties/FixedLength.java
===================================================================
--- java/org/apache/fop/fo/properties/FixedLength.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/FixedLength.java	(working copy)
@@ -45,7 +45,7 @@
     public static final String MPT = "mpt";
 
     /** cache holding all canonical FixedLength instances */
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(FixedLength.class);
     
     /** canonical zero-length instance */
     public static final FixedLength ZERO_FIXED_LENGTH = new FixedLength(0, FixedLength.MPT, 1.0f);
Index: java/org/apache/fop/fo/properties/FontFamilyProperty.java
===================================================================
--- java/org/apache/fop/fo/properties/FontFamilyProperty.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/FontFamilyProperty.java	(working copy)
@@ -31,7 +31,7 @@
 public final class FontFamilyProperty extends ListProperty {
 
     /** cache holding all canonical FontFamilyProperty instances */
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(FontFamilyProperty.class);
     
     private int hash = 0;
     
Index: java/org/apache/fop/fo/properties/KeepProperty.java
===================================================================
--- java/org/apache/fop/fo/properties/KeepProperty.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/KeepProperty.java	(working copy)
@@ -30,7 +30,7 @@
 public final class KeepProperty extends Property implements CompoundDatatype {
     
     /** class holding all canonical KeepProperty instances*/
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(KeepProperty.class);
     
     private boolean isCachedValue = false;
     private Property withinLine;
Index: java/org/apache/fop/fo/properties/NumberProperty.java
===================================================================
--- java/org/apache/fop/fo/properties/NumberProperty.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/NumberProperty.java	(working copy)
@@ -69,7 +69,7 @@
     }
 
     /** cache holding all canonical NumberProperty instances */
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(NumberProperty.class);
     
     private final Number number;
 
Index: java/org/apache/fop/fo/properties/PropertyCache.java
===================================================================
--- java/org/apache/fop/fo/properties/PropertyCache.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/PropertyCache.java	(working copy)
@@ -5,9 +5,9 @@
  * 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.
@@ -19,6 +19,8 @@
 
 package org.apache.fop.fo.properties;
 
+import org.apache.fop.fo.flow.Marker;
+
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
 
@@ -28,27 +30,38 @@
  *  The public access points are overloaded <code>fetch()</code> methods
  *  that each correspond to a cached type.
  *  It is designed especially to be used concurrently by multiple threads,
- *  drawing heavily upon the principles behind Java 1.5's 
- *  <code>ConcurrentHashMap</code>. 
+ *  drawing heavily upon the principles behind Java 1.5's
+ *  <code>ConcurrentHashMap</code>.
  */
 public final class PropertyCache {
 
-    /** bitmask to apply to the hash to get to the 
+    private static final int SEGMENT_COUNT = 32; //0x20
+    private static final int INITIAL_BUCKET_COUNT = SEGMENT_COUNT;
+
+    /** bitmask to apply to the hash to get to the
      *  corresponding cache segment */
-    private static final int SEGMENT_MASK = 0x1F;
-    
+    private static final int SEGMENT_MASK = SEGMENT_COUNT - 1; //0x1F
+    /**
+     * Indicates whether the cache should be used at all
+     * Can be controlled by the system property:
+     *   org.apache.fop.fo.properties.use-cache
+     */
+    private final boolean useCache;
+
     /** the segments array (length = 32) */
-    private CacheSegment[] segments = new CacheSegment[SEGMENT_MASK + 1];
+    private CacheSegment[] segments = new CacheSegment[SEGMENT_COUNT];
     /** the table of hash-buckets */
-    private CacheEntry[] table = new CacheEntry[8];
-    
-    boolean[] votesForRehash = new boolean[SEGMENT_MASK + 1];
-    
+    private CacheEntry[] table = new CacheEntry[INITIAL_BUCKET_COUNT];
+
+    private Class runtimeType;
+
+    private final boolean[] votesForRehash = new boolean[SEGMENT_COUNT];
+
     /* same hash function as used by java.util.HashMap */
     private static int hash(Object x) {
         return hash(x.hashCode());
     }
-    
+
     private static int hash(int hashCode) {
         int h = hashCode;
         h += ~(h << 9);
@@ -57,90 +70,95 @@
         h ^= (h >>> 10);
         return h;
     }
-    
+
     /* shortcut function */
     private static boolean eq(Object p, Object q) {
         return (p == q || (p != null && p.equals(q)));
     }
-    
+
     /* Class modeling a cached entry */
-    private final class CacheEntry extends WeakReference {
-        volatile CacheEntry nextEntry;
-        final int hash;
-        
+    private static class CacheEntry extends WeakReference {
+        private volatile CacheEntry nextEntry;
+        private final int hash;
+
         /* main constructor */
         public CacheEntry(Object p, CacheEntry nextEntry, ReferenceQueue refQueue) {
             super(p, refQueue);
             this.nextEntry = nextEntry;
-            this.hash = p.hashCode();
+            this.hash = hash(p);
         }
-        
+
+        /* main constructor */
+        public CacheEntry(Object p, CacheEntry nextEntry) {
+            super(p);
+            this.nextEntry = nextEntry;
+            this.hash = hash(p);
+        }
+
     }
-    
+
     /* Wrapper objects to synchronize on */
-    private final class CacheSegment {
+    private static class CacheSegment {
         private int count = 0;
-        private ReferenceQueue staleEntries = new ReferenceQueue();
-    }    
-    
-    private final void cleanSegment(int segmentIndex) {
-        CacheEntry entry;
+    }
+
+    private void cleanSegment(int segmentIndex) {
         CacheSegment segment = segments[segmentIndex];
-        int bucketIndex;
+
         int oldCount = segment.count;
 
-        while ((entry = (CacheEntry) segment.staleEntries.poll()) != null) {
-            bucketIndex = hash(entry.hash) & (table.length - 1);
-            /* remove obsolete entry */
-            /* 1. move to the corresponding entry */
+        /* clean all buckets in this segment */
+        for (int bucketIndex = segmentIndex;
+                    bucketIndex < table.length;
+                    bucketIndex += SEGMENT_COUNT) {
             CacheEntry prev = null;
-            CacheEntry e = table[bucketIndex];
-            while (e != null
-                    && e.nextEntry != null
-                    && e.hash != entry.hash) {
-                prev = e;
-                e = e.nextEntry;
+            CacheEntry entry = table[bucketIndex];
+            if (entry == null) {
+                continue;
             }
-            if (e != null) {
-                /* 2. remove reference from the chain */
-                if (prev == null) {
-                    table[bucketIndex] = e.nextEntry;
+            do {
+                if (entry.get() == null) {
+                    if (prev == null) {
+                        table[bucketIndex] = entry.nextEntry;
+                    } else {
+                        prev.nextEntry = entry.nextEntry;
+                    }
+                    segment.count--;
+                    assert segment.count >= 0;
                 } else {
-                    prev.nextEntry = e.nextEntry;
+                    prev = entry;
                 }
-                segment.count--;
-            }
+                entry = entry.nextEntry;
+            } while (entry != null);
         }
+
         synchronized (votesForRehash) {
             if (oldCount > segment.count) {
-                if (votesForRehash[segmentIndex]) {
-                    votesForRehash[segmentIndex] = false;
-                }
+                votesForRehash[segmentIndex] = false;
                 return;
-            } else {
-                /* cleanup had no effect */
-                if (!votesForRehash[segmentIndex]) {
-                    /* first time for this segment */
-                    votesForRehash[segmentIndex] = true;
-                    int voteCount = 0;
-                    for (int i = SEGMENT_MASK + 1; --i >= 0; ) {
-                        if (votesForRehash[i]) {
-                            voteCount++;
-                        }
+            }
+            /* cleanup had no effect */
+            if (!votesForRehash[segmentIndex]) {
+                /* first time for this segment */
+                votesForRehash[segmentIndex] = true;
+                int voteCount = 0;
+                for (int i = SEGMENT_MASK + 1; --i >= 0;) {
+                    if (votesForRehash[i]) {
+                        voteCount++;
                     }
-                    if (voteCount > SEGMENT_MASK / 4) {
-                        rehash(SEGMENT_MASK);
-                        /* reset votes */
-                        for (int i = SEGMENT_MASK + 1; --i >= 0;) {
-                            votesForRehash[i] = false;
-                        }
-    
+                }
+                if (voteCount > SEGMENT_MASK / 4) {
+                    rehash(SEGMENT_MASK);
+                    /* reset votes */
+                    for (int i = SEGMENT_MASK + 1; --i >= 0;) {
+                        votesForRehash[i] = false;
                     }
+
                 }
             }
         }
     }
-    
+
     /*
      * Puts a new instance in the cache.
      * If the total number of entries for the corresponding
@@ -148,17 +166,18 @@
      * cleanup will be performed to try and remove obsolete
      * entries.
      */
-    private final void put(Object o) {
-        
+    private void put(Object o) {
+
         int hash = hash(o);
-        CacheSegment segment = segments[hash & SEGMENT_MASK];
-        
+        int segmentIndex = hash & SEGMENT_MASK;
+        CacheSegment segment = segments[segmentIndex];
+
         synchronized (segment) {
             int index = hash & (table.length - 1);
             CacheEntry entry = table[index];
-            
+
             if (entry == null) {
-                entry = new CacheEntry(o, null, segment.staleEntries);
+                entry = new CacheEntry(o, null);
                 table[index] = entry;
                 segment.count++;
             } else {
@@ -166,37 +185,37 @@
                 if (eq(p, o)) {
                     return;
                 } else {
-                    CacheEntry newEntry = new CacheEntry(o, entry, segment.staleEntries);
+                    CacheEntry newEntry = new CacheEntry(o, entry);
                     table[index] = newEntry;
                     segment.count++;
                 }
             }
-            
+
             if (segment.count > (2 * table.length)) {
-                cleanSegment(hash & SEGMENT_MASK);
+                  cleanSegment(segmentIndex);
             }
         }
     }
-    
 
+
     /* Gets a cached instance. Returns null if not found */
-    private final Object get(Object o) {
-        
+    private Object get(Object o) {
+
         int hash = hash(o);
         int index = hash & (table.length - 1);
-        
+
         CacheEntry entry = table[index];
         Object q;
-        
+
         /* try non-synched first */
         for (CacheEntry e = entry; e != null; e = e.nextEntry) {
-            if (e.hash == o.hashCode()
+            if (e.hash == hash
                     && (q = e.get()) != null
                     &&  eq(q, o)) {
                 return q;
             }
         }
-        
+
         /* retry synched, only if the above attempt did not succeed,
          * as another thread may, in the meantime, have added a
          * corresponding entry */
@@ -204,7 +223,7 @@
         synchronized (segment) {
             entry = table[index];
             for (CacheEntry e = entry; e != null; e = e.nextEntry) {
-                if (e.hash == o.hashCode()
+                if (e.hash == hash
                         && (q = e.get()) != null
                         &&  eq(q, o)) {
                     return q;
@@ -213,14 +232,14 @@
         }
         return null;
     }
-    
+
     /*
      * Recursively acquires locks on all 32 segments,
      * extends the cache and redistributes the entries.
-     * 
+     *
      */
-    private final void rehash(int index) {
-        
+    private void rehash(int index) {
+
         CacheSegment seg = segments[index];
         synchronized (seg) {
             if (index > 0) {
@@ -230,13 +249,13 @@
                 /* double the amount of buckets */
                 int newLength = table.length << 1;
                 if (newLength > 0) { //no overflow?
-                    /* reset segmentcounts */
+                    /* reset segment counts */
                     for (int i = segments.length; --i >= 0;) {
                         segments[i].count = 0;
                     }
-                    
+
                     CacheEntry[] newTable = new CacheEntry[newLength];
-                    
+
                     int hash, idx;
                     Object o;
                     newLength--;
@@ -245,8 +264,7 @@
                             if ((o = c.get()) != null) {
                                 hash = c.hash;
                                 idx = hash & newLength;
-                                newTable[idx] = new CacheEntry(o, newTable[idx], 
-                                        segments[hash & SEGMENT_MASK].staleEntries);
+                                newTable[idx] = new CacheEntry(o, newTable[idx]);
                                 segments[hash & SEGMENT_MASK].count++;
                             }
                         }
@@ -256,87 +274,133 @@
             }
         }
     }
-    
+
     /**
-     *  Default constructor. 
+     *  Default constructor.
+     *
+     *  @param c    Runtime type of the objects that will be stored in the cache
      */
-    public PropertyCache() {
-        for (int i = SEGMENT_MASK + 1; --i >= 0;) {
-            segments[i] = new CacheSegment();
+    public PropertyCache(Class c) {
+        this.useCache = Boolean.valueOf(System.getProperty(
+                            "org.apache.fop.fo.properties.use-cache", "true")
+                        ).booleanValue();
+        if (useCache) {
+            for (int i = SEGMENT_MASK + 1; --i >= 0;) {
+                segments[i] = new CacheSegment();
+            }
         }
+        this.runtimeType = c;
     }
-    
+
     /**
      *  Generic fetch() method.
-     *  Checks if the given <code>Object</code> is present in the cache - 
-     *  if so, returns a reference to the cached instance. 
+     *  Checks if the given <code>Object</code> is present in the cache -
+     *  if so, returns a reference to the cached instance.
      *  Otherwise the given object is added to the cache and returned.
-     *  
+     *
      *  @param obj   the Object to check for
      *  @return  the cached instance
      */
-    private final Object fetch(Object obj) {
+    private Object fetch(Object obj) {
+        if (!this.useCache) {
+            return obj;
+        }
+
         if (obj == null) {
             return null;
         }
 
         Object cacheEntry = get(obj);
         if (cacheEntry != null) {
-            return cacheEntry;                
+            return cacheEntry;
         }
         put(obj);
         return obj;
     }
-    
+
     /**
-     *  Checks if the given <code>Property</code> is present in the cache - 
-     *  if so, returns a reference to the cached instance. 
+     *  Checks if the given {@link Property} is present in the cache -
+     *  if so, returns a reference to the cached instance.
      *  Otherwise the given object is added to the cache and returned.
-     *  
+     *
      *  @param prop the Property instance to check for
      *  @return the cached instance
      */
-    public final Property fetch(Property prop) {
-        
+    public Property fetch(Property prop) {
+
         return (Property) fetch((Object) prop);
     }
-    
+
     /**
-     *  Checks if the given <code>CommonHyphenation</code> is present in the cache - 
-     *  if so, returns a reference to the cached instance. 
+     *  Checks if the given {@link CommonHyphenation} is present in the cache -
+     *  if so, returns a reference to the cached instance.
      *  Otherwise the given object is added to the cache and returned.
-     *  
+     *
      *  @param chy the CommonHyphenation instance to check for
      *  @return the cached instance
      */
-    public final CommonHyphenation fetch(CommonHyphenation chy) {
-        
+    public CommonHyphenation fetch(CommonHyphenation chy) {
+
         return (CommonHyphenation) fetch((Object) chy);
     }
-    
+
     /**
-     *  Checks if the given <code>CachedCommonFont</code> is present in the cache - 
-     *  if so, returns a reference to the cached instance. 
+     *  Checks if the given {@link CommonFont} is present in the cache -
+     *  if so, returns a reference to the cached instance.
      *  Otherwise the given object is added to the cache and returned.
-     *  
-     *  @param ccf the CachedCommonFont instance to check for
+     *
+     *  @param cf the CommonFont instance to check for
      *  @return the cached instance
      */
-    public final CommonFont.CachedCommonFont fetch(CommonFont.CachedCommonFont ccf) {
-        
-        return (CommonFont.CachedCommonFont) fetch((Object) ccf);
+    public CommonFont fetch(CommonFont cf) {
+
+        return (CommonFont) fetch((Object) cf);
     }
+
+    /**
+     *  Checks if the given {@link CommonBorderPaddingBackground} is present in the cache -
+     *  if so, returns a reference to the cached instance.
+     *  Otherwise the given object is added to the cache and returned.
+     *
+     *  @param cbpb the CommonBorderPaddingBackground instance to check for
+     *  @return the cached instance
+     */
+    public CommonBorderPaddingBackground fetch(CommonBorderPaddingBackground cbpb) {
+
+        return (CommonBorderPaddingBackground) fetch((Object) cbpb);
+    }
+
+    /**
+     *  Checks if the given {@link CommonBorderPaddingBackground.BorderInfo} is present
+     *  in the cache - if so, returns a reference to the cached instance.
+     *  Otherwise the given object is added to the cache and returned.
+     *
+     *  @param bi the BorderInfo instance to check for
+     *  @return the cached instance
+     */
+    public CommonBorderPaddingBackground.BorderInfo fetch(
+            CommonBorderPaddingBackground.BorderInfo bi) {
+        return (CommonBorderPaddingBackground.BorderInfo) fetch((Object) bi);
+    }
     
     /**
-     *  Checks if the given <code>CommonFont</code> is present in the cache - 
-     *  if so, returns a reference to the cached instance. 
+     *  Checks if the given {@link Marker.MarkerAttribute} is present
+     *  in the cache - if so, returns a reference to the cached instance.
      *  Otherwise the given object is added to the cache and returned.
-     *  
-     *  @param cf the CommonFont instance to check for
+     *
+     *  @param ma the MarkerAttribute instance to check for
      *  @return the cached instance
      */
-    public final CommonFont fetch(CommonFont cf) {
-        
-        return (CommonFont) fetch((Object) cf);
+    public Marker.MarkerAttribute fetch(
+            Marker.MarkerAttribute ma) {
+        return (Marker.MarkerAttribute) fetch((Object) ma);
     }
+
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return super.toString() + "[runtimeType=" + this.runtimeType + "]";
+    }
+
+
 }
Index: java/org/apache/fop/fo/properties/StringProperty.java
===================================================================
--- java/org/apache/fop/fo/properties/StringProperty.java	(revision 723701)
+++ java/org/apache/fop/fo/properties/StringProperty.java	(working copy)
@@ -72,14 +72,17 @@
                     value = str;
                 }
             }
-            return new StringProperty(value);
+            return StringProperty.getInstance(value);
         }
 
-    }    // end String.Maker
+    }
 
     /** cache containing all canonical StringProperty instances */
-    private static final PropertyCache cache = new PropertyCache();
+    private static final PropertyCache cache = new PropertyCache(StringProperty.class);
     
+    /** canonical instance for empty strings */
+    public static final StringProperty EMPTY_STRING_PROPERTY = new StringProperty("");
+    
     private final String str;
 
     /**
@@ -97,40 +100,38 @@
      * @return  the canonical instance
      */
     public static StringProperty getInstance(String str) {
-        return (StringProperty)cache.fetch(
-                   new StringProperty(str));
+        if ("".equals(str) || str == null) {
+            return EMPTY_STRING_PROPERTY;
+        } else {
+            return (StringProperty)cache.fetch(
+                       new StringProperty(str));
+        }
     }
     
-    /**
-     * @return the Object equivalent of this property
-     */
+    /** @return the Object equivalent of this property */
     public Object getObject() {
         return this.str;
     }
 
-    /**
-     * @return the String equivalent of this property
-     */
+    /** @return the String equivalent of this property */
     public String getString() {
         return this.str;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
         if (obj instanceof StringProperty) {
             StringProperty sp = (StringProperty)obj;
             return (sp.str == this.str
                     || sp.str.equals(this.str));
-        } else {
-            return false;
         }
+        return false;
     }
     
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public int hashCode() {
         return str.hashCode();
     }
Index: java/org/apache/fop/fo/PropertyList.java
===================================================================
--- java/org/apache/fop/fo/PropertyList.java	(revision 723701)
+++ java/org/apache/fop/fo/PropertyList.java	(working copy)
@@ -581,7 +581,7 @@
      */
     public CommonBorderPaddingBackground getBorderPaddingBackgroundProps() 
                 throws PropertyException {
-        return new CommonBorderPaddingBackground(this);
+        return CommonBorderPaddingBackground.getInstance(this);
     }
     
     /**
Index: java/org/apache/fop/fo/XMLWhiteSpaceHandler.java
===================================================================
--- java/org/apache/fop/fo/XMLWhiteSpaceHandler.java	(revision 723701)
+++ java/org/apache/fop/fo/XMLWhiteSpaceHandler.java	(working copy)
@@ -27,7 +27,7 @@
 /**
  * Class encapsulating the functionality for white-space-handling
  * during refinement stage.
- * The <code>handleWhiteSpace()</code> methods are called during 
+ * The <code>handleWhiteSpace()</code> methods are called during
  * FOTree-building and marker-cloning:
  * <br>
  * <ul>
@@ -47,8 +47,8 @@
  *      after the previous non-text child</li>
  * </ul>
  * <br>
- * The iteration always starts at <code>firstTextNode</code>, 
- * goes on until the last text-node is reached, and deals only 
+ * The iteration always starts at <code>firstTextNode</code>,
+ * goes on until the last text-node is reached, and deals only
  * with <code>FOText</code> or <code>Character</code> nodes.
  * <br>
  * <em>Note</em>: if the method is called from an inline's endOfNode(),
@@ -60,25 +60,25 @@
  *   of the ancestor block.
  */
 public class XMLWhiteSpaceHandler {
-    
+
     /** True if we are in a run of white space */
     private boolean inWhiteSpace = false;
     /** True if the last char was a linefeed */
     private boolean afterLinefeed = true;
     /** Counter, increased every time a non-white-space is encountered */
     private int nonWhiteSpaceCount;
-    
+
     private int linefeedTreatment;
     private int whiteSpaceTreatment;
     private int whiteSpaceCollapse;
     private boolean endOfBlock;
     private boolean nextChildIsBlockLevel;
     private RecursiveCharIterator charIter;
-    
+
     private List pendingInlines;
     private Stack nestedBlockStack = new java.util.Stack();
     private CharIterator firstWhiteSpaceInSeq;
-    
+
     /**
      * Handle white-space for the fo that is passed in, starting at
      * firstTextNode
@@ -87,40 +87,51 @@
      * @param nextChild the node that will be added to the list
      *                  after firstTextNode
      */
-    public void handleWhiteSpace(FObjMixed fo, FONode firstTextNode, FONode nextChild) {
-        
+    public void handleWhiteSpace(FObjMixed fo,
+                                 FONode firstTextNode,
+                                 FONode nextChild) {
+
         Block currentBlock = null;
         int foId = fo.getNameId();
-        
-        if (foId == Constants.FO_BLOCK) {
-            currentBlock = (Block) fo;
-            if (nestedBlockStack.isEmpty() || fo != nestedBlockStack.peek()) {
-                if (nextChild != null) {
-                    /* if already in a block, push the current block 
-                     * onto the stack of nested blocks
-                     */
+
+        /* set the current block */
+        switch (foId) {
+            case Constants.FO_BLOCK:
+                currentBlock = (Block) fo;
+                if (nestedBlockStack.empty() || fo != nestedBlockStack.peek()) {
+                    if (nextChild != null) {
+                        /* if already in a block, push the current block
+                         * onto the stack of nested blocks
+                         */
+                        nestedBlockStack.push(currentBlock);
+                    }
+                } else {
+                    if (nextChild == null) {
+                        nestedBlockStack.pop();
+                    }
+                }
+                break;
+
+            case Constants.FO_RETRIEVE_MARKER:
+                /* look for the nearest block ancestor, if any */
+                FONode ancestor = fo;
+                do {
+                    ancestor = ancestor.getParent();
+                } while (ancestor.getNameId() != Constants.FO_BLOCK
+                        && ancestor.getNameId() != Constants.FO_STATIC_CONTENT);
+
+                if (ancestor.getNameId() == Constants.FO_BLOCK) {
+                    currentBlock = (Block) ancestor;
                     nestedBlockStack.push(currentBlock);
                 }
-            } else {
-                if (nextChild == null) {
-                    nestedBlockStack.pop();
+                break;
+
+            default:
+                if (!nestedBlockStack.empty()) {
+                    currentBlock = (Block) nestedBlockStack.peek();
                 }
-            }
-        } else if (foId == Constants.FO_RETRIEVE_MARKER) {
-            /* look for the nearest block ancestor, if any */
-            FONode ancestor = fo;
-            do {
-                ancestor = ancestor.getParent();
-            } while (ancestor.getNameId() != Constants.FO_BLOCK
-                    && ancestor.getNameId() != Constants.FO_STATIC_CONTENT);
-            
-            if (ancestor.getNameId() == Constants.FO_BLOCK) {
-                currentBlock = (Block) ancestor;
-            }
-        } else if (!nestedBlockStack.isEmpty()) {
-            currentBlock = (Block) nestedBlockStack.peek();
         }
-        
+
         if (currentBlock != null) {
             linefeedTreatment = currentBlock.getLinefeedTreatment();
             whiteSpaceCollapse = currentBlock.getWhitespaceCollapse();
@@ -130,27 +141,53 @@
             whiteSpaceCollapse = Constants.EN_TRUE;
             whiteSpaceTreatment = Constants.EN_IGNORE_IF_SURROUNDING_LINEFEED;
         }
-        
+
+        endOfBlock = (nextChild == null && fo == currentBlock);
+
         if (firstTextNode == null) {
-            //nothing to do but initialize related properties
+            //no text means no white-space to handle; return early
+            afterLinefeed = (fo == currentBlock && fo.firstChild == null);
+            nonWhiteSpaceCount = 0;
+            if (endOfBlock) {
+                handlePendingInlines();
+            }
             return;
         }
-        
+
         charIter = new RecursiveCharIterator(fo, firstTextNode);
         inWhiteSpace = false;
-        
+
         if (fo == currentBlock
                 || currentBlock == null
                 || (foId == Constants.FO_RETRIEVE_MARKER
                         && fo.getParent() == currentBlock)) {
-            afterLinefeed = (
-                    (firstTextNode == fo.firstChild)
-                        || (firstTextNode.siblings[0].getNameId()
-                                == Constants.FO_BLOCK));
+            if (firstTextNode == fo.firstChild) {
+                afterLinefeed = true;
+            } else {
+                int previousChildId = firstTextNode.siblings[0].getNameId();
+                afterLinefeed = (previousChildId == Constants.FO_BLOCK
+                        || previousChildId == Constants.FO_TABLE_AND_CAPTION
+                        || previousChildId == Constants.FO_TABLE
+                        || previousChildId == Constants.FO_LIST_BLOCK
+                        || previousChildId == Constants.FO_BLOCK_CONTAINER);
+            }
         }
-        
-        endOfBlock = (nextChild == null && fo == currentBlock);
-        
+
+        if (foId == Constants.FO_WRAPPER) {
+            FONode parent = fo.parent;
+            int parentId = parent.getNameId();
+            while (parentId == Constants.FO_WRAPPER) {
+                parent = parent.parent;
+                parentId = parent.getNameId();
+            }
+            if (parentId == Constants.FO_FLOW
+                    || parentId == Constants.FO_STATIC_CONTENT
+                    || parentId == Constants.FO_BLOCK_CONTAINER
+                    || parentId == Constants.FO_TABLE_CELL) {
+                endOfBlock = (nextChild == null);
+            }
+        }
+
         if (nextChild != null) {
             int nextChildId = nextChild.getNameId();
             nextChildIsBlockLevel = (
@@ -162,38 +199,20 @@
         } else {
             nextChildIsBlockLevel = false;
         }
-        
+
         handleWhiteSpace();
-        
-        if (fo == currentBlock 
-                && pendingInlines != null 
-                && !pendingInlines.isEmpty()) {
-            /* current FO is a block, and has pending inlines */
-            if (endOfBlock || nextChildIsBlockLevel) {
-                if (nonWhiteSpaceCount == 0) {
-                    /* handle white-space for all pending inlines*/
-                    PendingInline p;
-                    for (int i = pendingInlines.size(); --i >= 0;) {
-                        p = (PendingInline)pendingInlines.get(i);
-                        charIter = (RecursiveCharIterator)p.firstTrailingWhiteSpace;
-                        handleWhiteSpace();
-                        pendingInlines.remove(p);
-                    }
-                } else {
-                    /* there is non-white-space text between the pending
-                     * inline(s) and the end of the block;
-                     * clear list of pending inlines */
-                    pendingInlines.clear();
-                }
-            }
+
+        if (fo == currentBlock
+                && (endOfBlock || nextChildIsBlockLevel)) {
+            handlePendingInlines();
         }
-        
+
         if (nextChild == null) {
             if (fo != currentBlock) {
                 /* current FO is not a block, and is about to end */
                 if (nonWhiteSpaceCount > 0 && pendingInlines != null) {
-                    /* there is non-white-space text between the pending 
-                     * inline(s) and the end of the non-block node; 
+                    /* there is non-white-space text between the pending
+                     * inline(s) and the end of the non-block node;
                      * clear list of pending inlines */
                     pendingInlines.clear();
                 }
@@ -203,36 +222,33 @@
                     addPendingInline(fo);
                 }
             } else {
-                /* end of block: clear the references and pop the 
+                /* end of block: clear the references and pop the
                  * nested block stack */
                 if (!nestedBlockStack.empty()) {
-                    currentBlock = (Block) nestedBlockStack.pop();
-                } else {
-                    currentBlock = null;
+                    nestedBlockStack.pop();
                 }
                 charIter = null;
+                firstWhiteSpaceInSeq = null;
             }
         }
     }
-    
+
     /**
      * Handle white-space for the fo that is passed in, starting at
      * firstTextNode (when a nested FO is encountered)
      * @param fo    the FO for which to handle white-space
      * @param firstTextNode the node at which to start
-     * @param nextChild the child-node that will be added to the list after
-     *                  the last text-node
      */
     public void handleWhiteSpace(FObjMixed fo, FONode firstTextNode) {
         handleWhiteSpace(fo, firstTextNode, null);
     }
-    
+
     private void handleWhiteSpace() {
-        
+
         EOLchecker lfCheck = new EOLchecker(charIter);
-        
+
         nonWhiteSpaceCount = 0;
-        
+
         while (charIter.hasNext()) {
             if (!inWhiteSpace) {
                 firstWhiteSpaceInSeq = charIter.mark();
@@ -250,7 +266,7 @@
             switch (CharUtilities.classOf(currentChar)) {
                 case CharUtilities.XMLWHITESPACE:
                     // Some kind of whitespace character, except linefeed.
-                    if (inWhiteSpace 
+                    if (inWhiteSpace
                             && whiteSpaceCollapse == Constants.EN_TRUE) {
                         // We are in a run of whitespace and should collapse
                         // Just delete the char
@@ -328,14 +344,34 @@
             }
         }
     }
-    
+
     private void addPendingInline(FObjMixed fo) {
         if (pendingInlines == null) {
             pendingInlines = new java.util.ArrayList(5);
         }
         pendingInlines.add(new PendingInline(fo, firstWhiteSpaceInSeq));
     }
-    
+
+    private void handlePendingInlines() {
+        if (!(pendingInlines == null || pendingInlines.isEmpty())) {
+            if (nonWhiteSpaceCount == 0) {
+                /* handle white-space for all pending inlines*/
+                PendingInline p;
+                for (int i = pendingInlines.size(); --i >= 0;) {
+                    p = (PendingInline)pendingInlines.get(i);
+                    charIter = (RecursiveCharIterator)p.firstTrailingWhiteSpace;
+                    handleWhiteSpace();
+                    pendingInlines.remove(p);
+                }
+            } else {
+                /* there is non-white-space text between the pending
+                 * inline(s) and the end of the block;
+                 * clear list of pending inlines */
+                pendingInlines.clear();
+            }
+        }
+    }
+
     /**
      * Helper class, used during white-space handling to look ahead, and
      * see if the next character is a linefeed (or if there will be
@@ -366,7 +402,7 @@
                 }
                 // No more characters == end of text run
                 // means EOL if there either is a nested block to be added,
-                // or if this is the last text node in the current block   
+                // or if this is the last text node in the current block
                 nextIsEOL = nextChildIsBlockLevel || endOfBlock;
             }
             return nextIsEOL;
@@ -376,16 +412,16 @@
             nextIsEOL = false;
         }
     }
-    
+
     /**
-     * Helper class to store unfinished inline nodes together 
+     * Helper class to store unfinished inline nodes together
      * with an iterator that starts at the first white-space
      * character in the sequence of trailing white-space
      */
     private class PendingInline {
         protected FObjMixed fo;
         protected CharIterator firstTrailingWhiteSpace;
-        
+
         PendingInline(FObjMixed fo, CharIterator firstTrailingWhiteSpace) {
             this.fo = fo;
             this.firstTrailingWhiteSpace = firstTrailingWhiteSpace;
