Index: fop
===================================================================
--- fop	(revision 532293)
+++ fop	(working copy)
@@ -243,7 +243,12 @@
 
 # Execute FOP using eval/exec to preserve spaces in paths,
 # java options, and FOP args
-fop_exec_command="exec \"$JAVACMD\" $LOGCHOICE $LOGLEVEL -classpath \"$LOCALCLASSPATH\" $FOP_OPTS org.apache.fop.cli.Main $fop_exec_args"
+
+# Add the following options for extra debug:
+# JMP: -Xrunjmp
+# Hat: -Xrunhprof:file=dump.hprof,format=b
+
+fop_exec_command="exec \"$JAVACMD\" -Xrunhprof:file=dump.hprof,format=b $LOGCHOICE $LOGLEVEL -classpath \"$LOCALCLASSPATH\" $FOP_OPTS org.apache.fop.cli.Main $fop_exec_args"
 if $fop_exec_debug ; then
     echo $fop_exec_command
 fi
Index: src/java/org/apache/fop/render/txt/TXTFOEventHandlerMaker.java
===================================================================
--- src/java/org/apache/fop/render/txt/TXTFOEventHandlerMaker.java	(revision 532293)
+++ src/java/org/apache/fop/render/txt/TXTFOEventHandlerMaker.java	(working copy)
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.txt;
-
-import java.io.OutputStream;
-
-import org.apache.fop.apps.FOPException;
-import org.apache.fop.apps.FOUserAgent;
-import org.apache.fop.apps.MimeConstants;
-import org.apache.fop.fo.FOEventHandler;
-import org.apache.fop.render.AbstractFOEventHandlerMaker;
-
-/**
- * Maker class for the special FOEventHandler for TXT support.
- */
-public class TXTFOEventHandlerMaker extends AbstractFOEventHandlerMaker {
-
-    private static final String[] MIMES = new String[] {
-        MimeConstants.MIME_PLAIN_TEXT};
-    
-    /** @see org.apache.fop.render.AbstractFOEventHandlerMaker */
-    public FOEventHandler makeFOEventHandler(FOUserAgent ua, OutputStream out) throws FOPException {
-        return new TXTHandler(ua, out);
-    }
-
-    /** @see org.apache.fop.render.AbstractFOEventHandlerMaker#needsOutputStream() */
-    public boolean needsOutputStream() {
-        return true;
-    }
-
-    /** @see org.apache.fop.render.AbstractFOEventHandlerMaker#getSupportedMimeTypes() */
-    public String[] getSupportedMimeTypes() {
-        return MIMES;
-    }
-
-}
Index: src/java/org/apache/fop/render/txt/TXTHandler.java
===================================================================
--- src/java/org/apache/fop/render/txt/TXTHandler.java	(revision 532293)
+++ src/java/org/apache/fop/render/txt/TXTHandler.java	(working copy)
@@ -1,572 +0,0 @@
-/*
- * 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.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.txt;
-
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.fop.apps.FOPException;
-import org.apache.fop.apps.FOUserAgent;
-import org.apache.fop.apps.MimeConstants;
-import org.apache.fop.area.AreaTreeHandler;
-import org.apache.fop.datatypes.CompoundDatatype;
-import org.apache.fop.datatypes.Length;
-import org.apache.fop.datatypes.PercentBaseContext;
-import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.FONode;
-import org.apache.fop.fo.FOText;
-import org.apache.fop.fo.expr.NumericProperty;
-import org.apache.fop.fo.expr.RelativeNumericProperty;
-import org.apache.fop.fo.flow.Block;
-import org.apache.fop.fo.flow.BlockContainer;
-import org.apache.fop.fo.flow.ExternalGraphic;
-import org.apache.fop.fo.flow.Inline;
-import org.apache.fop.fo.flow.ListBlock;
-import org.apache.fop.fo.flow.ListItem;
-import org.apache.fop.fo.flow.PageNumber;
-import org.apache.fop.fo.flow.Table;
-import org.apache.fop.fo.flow.TableCell;
-import org.apache.fop.fo.flow.TableColumn;
-import org.apache.fop.fo.pagination.PageSequence;
-import org.apache.fop.fo.properties.CommonAbsolutePosition;
-import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
-import org.apache.fop.fo.properties.CommonFont;
-import org.apache.fop.fo.properties.CommonMarginBlock;
-import org.apache.fop.fo.properties.FixedLength;
-import org.apache.fop.fo.properties.Property;
-import org.apache.fop.fo.properties.SpaceProperty;
-import org.apache.fop.layoutmgr.BlockLayoutManager;
-
-/**
- * Handler for formatting objects in case of rendering to txt.
- * 
- * This handler gets page-sequence, modifies formatting objects and return them
- * to superclass. So areas are generated from modified FO. Idea of modifying is
- * to quantize FO properties, making them divisible by width of char or height 
- * of char.
- */
-public class TXTHandler extends AreaTreeHandler {
-
-    /** Percent base context. Needed for line-height. */
-    private static final PercentBaseContext CONTEXT 
-        = new BlockLayoutManager(new Block(null));
-
-    /** Modified font size in millipoints. */
-    private static final int MODIFIED_FONT_SIZE = 10000;
-
-    /** Quantum for each side (BEFORE, AFTER, START, END). */
-    private final int[] quantum = {TXTRenderer.CHAR_HEIGHT,
-            TXTRenderer.CHAR_HEIGHT, TXTRenderer.CHAR_WIDTH,
-            TXTRenderer.CHAR_WIDTH};
-
-    /** Keeps overpatching for each side. */
-    private int[] overPatching = new int[4];
-
-    /**
-     * Keeps last overpatching for each side. Needed for selective modifying of
-     * start-indent and end-indent.
-     */
-    private int[] lastOverPatching = new int[4];
-
-    /**
-     * Constructs a newly allocated <code>TXTHandler</code> object.
-     * 
-     * @param userAgent FOUserAgent
-     * @param stream OutputStream
-     * @throws FOPException if the RenderPagesModel cannot be created
-     */
-    public TXTHandler(FOUserAgent userAgent, OutputStream stream)
-            throws FOPException {
-        super(userAgent, MimeConstants.MIME_PLAIN_TEXT, stream);
-    }
-
-    /**
-     * Sets a component <code>CP_LENGTH</code> of <code>cd</code> to
-     * <code>value</code>.
-
-     * @param cd  CompoundDatatype
-     * @param value  new integer value
-     */
-    private static void setLength(CompoundDatatype cd, int value) {
-        cd.setComponent(Constants.CP_LENGTH, new FixedLength(value), true);
-    }
-
-    /**
-     * Sets components <code>CP_MINIMUM, CP_OPTIMUM, CP_MAXIMUM</code> of
-     * <code>cd</code> to <code>p</code>.
-     * 
-     * @param cd instance of CompoundDatatype for modifying.
-     * @param p  property for setting.
-     */
-    private static void setMinOptMax(CompoundDatatype cd, Property p) {
-        cd.setComponent(Constants.CP_MINIMUM, p, true);
-        cd.setComponent(Constants.CP_OPTIMUM, p, true);
-        cd.setComponent(Constants.CP_MAXIMUM, p, true);
-    }
-
-    /**
-     * Modifies border of side. If there is no border of given side, does
-     * nothing, otherwise sets border-width to half of char width or char height
-     * depending on side. <p> 
-     * Difference between values of new border-width and old border-width is 
-     * saved in <code>lastOverPatching</code>.
-     * 
-     * @param side side to modify.
-     * @param bpb instance of CommonBorderPaddingBackground for modifying.
-     */
-    private void modifyBorder(int side, CommonBorderPaddingBackground bpb) {
-        CommonBorderPaddingBackground.BorderInfo bi = bpb.getBorderInfo(side);
-
-        if (bi != null) {
-            int width = bpb.getBorderWidth(side, false);
-            setLength(bi.getWidth(), quantum[side] / 2);
-            lastOverPatching[side] += bpb.getBorderWidth(side, false) - width;
-        }
-    }
-
-    /**
-     * Modifies padding of side. First rounds padding to nearest integer,
-     * divisible by char width or char height depending on side. If border of
-     * given side is available, modifies padding in such a way, so sum of border
-     * width and padding will be divisible by char width or char height,
-     * depending on side. <p>
-     * Difference between values of new padding and old padding is saved 
-     * in <code>lastOverPatching</code>.
-     * 
-     * @param side side to modify.
-     * @param bpb instance of CommonBorderPaddingBackground for modifying.
-     */
-    private void modifyPadding(int side, CommonBorderPaddingBackground bpb) {
-        int oldPadding = bpb.getPadding(side, false, null);
-        int newPadding = Helper.round(oldPadding, quantum[side]);
-        if (bpb.getBorderInfo(side) != null) {
-            newPadding = Math.max(newPadding, quantum[side])
-                    - bpb.getBorderWidth(side, false);
-        }
-
-        setLength(bpb.getPaddingLengthProperty(side), newPadding);
-        lastOverPatching[side] += newPadding - oldPadding;
-    }
-
-    /**
-     * Modifies borders and paddings of <code>bpb</code>.
-     * 
-     * @param bpb instance of CommonBorderPaddingBackground for modifying.
-     */
-    private void modifyBPB(CommonBorderPaddingBackground bpb) {
-        modifyBorder(CommonBorderPaddingBackground.BEFORE, bpb);
-        modifyBorder(CommonBorderPaddingBackground.AFTER, bpb);
-        modifyBorder(CommonBorderPaddingBackground.START, bpb);
-        modifyBorder(CommonBorderPaddingBackground.END, bpb);
-
-        modifyPadding(CommonBorderPaddingBackground.BEFORE, bpb);
-        modifyPadding(CommonBorderPaddingBackground.AFTER, bpb);
-        modifyPadding(CommonBorderPaddingBackground.START, bpb);
-        modifyPadding(CommonBorderPaddingBackground.END, bpb);
-    }
-
-    /**
-     * Rounds optimum value of <code>space</code> to nearest integer,
-     * divisible by <code>q</code>.
-     * 
-     * @param space instance of SpaceProperty.
-     * @param q integer.
-     */
-    private void modifySpace(SpaceProperty space, int q) {
-        int value = space.getOptimum(null).getLength().getValue();
-        setMinOptMax(space, new FixedLength(Helper.round(value, q)));
-    }
-
-    /**
-     * @param length instance of Length.
-     * @param q integer.
-     * @return instance of Length, having value nearest to value of
-     *         <code>length</code>, and divisible by <code>q</code>.
-     */
-    private Length roundLength(Length length, int q) {
-        int x = Helper.round(length.getValue(), q);
-        return new FixedLength(x);
-    }
-
-    /**
-     * @param length instance of Length.
-     * @param q integer.
-     * @return instance of Length, having minimal value, greater value of
-     *         <code>length</code>, and divisible by <code>q</code>.
-     */
-    private Length ceilLength(Length length, int q) {
-        int x = Helper.ceil(length.getValue(), q);
-        return new FixedLength(x);
-    }
-
-    /**
-     * Modifies indent for given side. Summarizes value of indent and modifing
-     * error (i.e. overPatching). Rounds result to nearest integer, divisible by
-     * quantum.
-     * 
-     * @param indent Length to modify.
-     * @param side an integer, representing side.
-     * @return modified Length.
-     */
-    private Length modifyIndent(Length indent, int side) {
-        if (indent instanceof NumericProperty) {
-            overPatching[side] += lastOverPatching[side];
-        }
-        int newValue = indent.getValue() + overPatching[side];
-        newValue = Helper.round(newValue, quantum[side]);
-        return new FixedLength(newValue);
-    }
-
-    /**
-     * Modifies Common Margin Properties-Block:
-     * <ul>
-     * <li>margin-top, margin-left, margin-bottom, margin-right
-     * <li>start-indent, end-indent
-     * <li>space-before, space-after.
-     * </ul>
-     * 
-     * @param cmb instance of CommonMarginBlock to modify.
-     */
-    private void modifyCommonMarginBlock(CommonMarginBlock cmb) {
-        cmb.marginTop = roundLength(cmb.marginTop, TXTRenderer.CHAR_HEIGHT);
-        cmb.marginBottom = roundLength(cmb.marginBottom,
-                TXTRenderer.CHAR_HEIGHT);
-        cmb.marginLeft = roundLength(cmb.marginLeft, TXTRenderer.CHAR_WIDTH);
-        cmb.marginRight = roundLength(cmb.marginRight, TXTRenderer.CHAR_WIDTH);
-
-        modifySpace(cmb.spaceBefore, TXTRenderer.CHAR_HEIGHT);
-        modifySpace(cmb.spaceAfter, TXTRenderer.CHAR_HEIGHT);
-
-        if (!(cmb.startIndent instanceof RelativeNumericProperty)) {
-            cmb.startIndent = modifyIndent(cmb.startIndent,
-                    CommonBorderPaddingBackground.START);
-        }
-        if (!(cmb.endIndent instanceof RelativeNumericProperty)) {
-            cmb.endIndent = modifyIndent(cmb.endIndent,
-                    CommonBorderPaddingBackground.END);
-        }
-    }
-
-    /**
-     * Modifies fo:table attributes:
-     * <ul>
-     * <li>Common Margin Properties Block
-     * <li>Common Border, Padding, and Background Properties
-     * <li>columns.
-     * </ul>
-     * 
-     * @param table Table to modify.
-     */
-    private void modifyTable(Table table) {
-        CommonMarginBlock cmb = table.getCommonMarginBlock();
-        if (table.getBorderCollapse() == Constants.EN_COLLAPSE) {
-            // If border-collapse == "collapse", add space-after in order to
-            // impove interaction with other FO.
-            int value = cmb.spaceAfter.getOptimum(null).getLength().getValue();
-            value += TXTRenderer.CHAR_HEIGHT;
-            setMinOptMax(cmb.spaceAfter, new FixedLength(value));
-        }
-        modifyCommonMarginBlock(cmb);
-
-        modifyBPB(table.getCommonBorderPaddingBackground());
-
-        // modify all table-columns
-        List columnList = table.getColumns();
-        Iterator iter = columnList.iterator();
-        while (iter.hasNext()) {
-            modifyTableColumn((TableColumn) iter.next());
-        }
-    }
-
-    /**
-     * Modifies fo:table-column attributes:
-     * <ul>
-     * <li>width.
-     * </ul>
-     * 
-     * @param column TableColumn to modify.
-     */
-    private void modifyTableColumn(TableColumn column) {
-        column.setColumnWidth(ceilLength(column.getColumnWidth(), 
-                TXTRenderer.CHAR_WIDTH));
-    }
-
-    /**
-     * Modifies padding of fo:table-cell.
-     * 
-     * @param side side.
-     * @param bpb instance of CommonBorderPaddingBackground to modify.
-     */
-    private void modifyCellPadding(int side, CommonBorderPaddingBackground bpb) {
-        if (bpb.getBorderInfo(side) == null) {
-            int oldPadding = bpb.getPadding(side, false, null);
-            int newPadding = oldPadding + quantum[side] / 2;
-            setLength(bpb.getPaddingLengthProperty(side), newPadding);
-        }
-    }
-
-    /**
-     * Modifies table-cell properties:
-     * <ul>
-     * <li>Common Border, Padding, and Background Properties.
-     * </ul>
-     * 
-     * @param c TableCell to modify.
-     */
-    private void modifyTableCell(TableCell c) {
-        CommonBorderPaddingBackground bpb = c
-                .getCommonBorderPaddingBackground();
-        modifyBPB(bpb);
-        modifyCellPadding(CommonBorderPaddingBackground.BEFORE, bpb);
-        modifyCellPadding(CommonBorderPaddingBackground.AFTER, bpb);
-        modifyCellPadding(CommonBorderPaddingBackground.START, bpb);
-        modifyCellPadding(CommonBorderPaddingBackground.END, bpb);
-    }
-
-    /**
-     * Modifies Common Absolute Position Properties:
-     * <ul>
-     * <li>left
-     * <li>top.
-     * </ul>
-     * 
-     * @param cap CommonAbsolutePosition to modify.
-     */
-    private void modifyCommonAbsolutePosition(CommonAbsolutePosition cap) {
-        if (cap.absolutePosition == Constants.EN_ABSOLUTE) {
-            cap.left = roundLength(cap.left, TXTRenderer.CHAR_WIDTH);
-            cap.top = roundLength(cap.top, TXTRenderer.CHAR_HEIGHT);
-        }
-    }
-
-    /**
-     * Modifies line-height property. Sets a value of line-height to max(char
-     * height; lowest integer, divisible by char height).
-     * 
-     * @param lineHeight SpaceProperty to modify.
-     */
-    private void modifyLineHeight(SpaceProperty lineHeight) {
-        Property p = lineHeight.getOptimum(null);
-        int value = p.getLength().getValue(CONTEXT);
-
-        int height = TXTRenderer.CHAR_HEIGHT;
-        int newValue = Math.max(Helper.floor(value, height), height);
-        setMinOptMax(lineHeight, new FixedLength(newValue));
-    }
-
-    /**
-     * Modifies Common Font Properties:
-     * <ul>
-     * <li>font-family = Courier;
-     * <li>font-size = MODIFIED_FONT_SIZE;
-     * <li>font-stretch = EN_NORMAL;
-     * <li>font-weight = EN_NORMAL.
-     * </ul>
-     * 
-     * @param cf the font to modify.
-     */
-    private void modifyCommonFont(CommonFont cf) {
-        if (cf != null) {
-            cf.overrideFontFamily("Courier");
-            cf.fontSize = new FixedLength(MODIFIED_FONT_SIZE);
-            cf.fontStretch = Constants.EN_NORMAL;
-            cf.fontWeight = Constants.EN_NORMAL;
-        }
-    }
-
-    /**
-     * Modifies fo:block:
-     * <ul>
-     * <li>Common Border, Padding, and Background Properties
-     * <li>Common Margin Properties-Block
-     * <li>Common Font Properties
-     * <li>line-height.
-     * </ul>
-     * 
-     * @param block Block to modify.
-     */
-    private void modifyBlock(Block block) {
-        modifyBPB(block.getCommonBorderPaddingBackground());
-        modifyCommonMarginBlock(block.getCommonMarginBlock());
-        modifyCommonFont(block.getCommonFont());
-        modifyLineHeight(block.getLineHeight());
-    }
-
-    /**
-     * Modifies fo:block-container:
-     * <ul>
-     * <li>Common Border, Padding, and Background Properties
-     * <li>Common Margin Properties-Block
-     * <li>Common Absolute Position Properties.
-     * </ul>
-     * 
-     * @param bc BlockContainer to modify.
-     */
-    private void modifyBlockContainer(BlockContainer bc) {
-        modifyBPB(bc.getCommonBorderPaddingBackground());
-        modifyCommonMarginBlock(bc.getCommonMarginBlock());
-        modifyCommonAbsolutePosition(bc.getCommonAbsolutePosition());
-    }
-
-    /**
-     * Modifies fo:inline:
-     * <ul>
-     * <li>Common Font Properties
-     * </ul>
-     * 
-     * @param inline Inline to modify.
-     */
-    private void modifyInline(Inline inline) {
-        modifyCommonFont(inline.getCommonFont());
-    }
-
-    /**
-     * Modifies FOText:
-     * <ul>
-     * <li>Common Font Properties
-     * </ul>
-     * 
-     * @param text FOText to modify.
-     */
-    private void modifyFOText(FOText text) {
-        modifyCommonFont(text.getCommonFont());
-    }
-
-    /**
-     * Modifies fo:external-graphic:
-     * <ul>
-     * <li>Common Border, Padding, and Background Properties
-     * <li>line-height.
-     * </ul>
-     * 
-     * @param eg ExternalGraphic to modify.
-     */
-    private void modifyExternalGraphic(ExternalGraphic eg) {
-        modifyBPB(eg.getCommonBorderPaddingBackground());
-        modifyLineHeight(eg.getLineHeight());
-    }
-
-    /**
-     * Modifies fo:list-block:
-     * <ul>
-     * <li>Common Border, Padding, and Background Properties
-     * <li>Common Margin Properties-Block.
-     * </ul>
-     * 
-     * @param lb ListBlock to modify.
-     */
-    private void modifyListBlock(ListBlock lb) {
-        modifyBPB(lb.getCommonBorderPaddingBackground());
-        modifyCommonMarginBlock(lb.getCommonMarginBlock());
-    }
-
-    /**
-     * Modifies fo:list-item:
-     * <ul>
-     * <li>Common Border, Padding, and Background Properties
-     * <li>Common Margin Properties-Block.
-     * </ul>
-     * <p>
-     * Make refinement for fo:list-item-label and fo:list-item-body.
-     * 
-     * @param li ListItem to modify.
-     */
-    private void modifyListItem(ListItem li) {
-        modifyBPB(li.getCommonBorderPaddingBackground());
-        modifyCommonMarginBlock(li.getCommonMarginBlock());
-        refinement(li.getLabel());
-        refinement(li.getBody());
-    }
-    
-    /**
-     * Does refinement for particular node. Modifies node's properties and
-     * refines its children recursively.
-     * 
-     * @param node the node to refine.
-     */
-    private void refinement(FONode node) {
-        int[] saveOverPatching = (int[]) overPatching.clone();
-        Arrays.fill(lastOverPatching, 0);
-
-        if (node instanceof Block) {
-            modifyBlock((Block) node);
-        } else if (node instanceof BlockContainer) {
-            modifyBlockContainer((BlockContainer) node);
-        } else if (node instanceof Inline) {
-            modifyInline((Inline) node);
-        } else if (node instanceof FOText) {
-            modifyFOText((FOText) node);
-        } else if (node instanceof Table) {
-            modifyTable((Table) node);
-            Arrays.fill(overPatching, 0);
-        } else if (node instanceof TableCell) {
-            modifyTableCell((TableCell) node);
-        } else if (node instanceof ExternalGraphic) {
-            modifyExternalGraphic((ExternalGraphic) node);
-        } else if (node instanceof ListBlock) {
-            modifyListBlock((ListBlock) node);
-        } else if (node instanceof ListItem) {
-            modifyListItem((ListItem) node);
-        } else if (node instanceof PageNumber) {
-            modifyCommonFont(((PageNumber) node).getCommonFont());
-        }
-
-        Iterator it = node.getChildNodes();
-        if (it != null) {
-            while (it.hasNext()) {
-                refinement((FONode) it.next());
-            }
-        }
-        overPatching = saveOverPatching;
-    }
-
-    /**
-     * Run refinement for:
-     * <ul>
-     * <li>mainflow (xsl-region-body)
-     * <li>staticflow (xsl-region-before, xsl-region-after, xsl-region-start,
-     * xsl-region-end).
-     * </ul>
-     * 
-     * @param pageSequence PageSequence to refine.
-     */
-    public void endPageSequence(PageSequence pageSequence) {
-        Arrays.fill(overPatching, 0);
-
-        refinement(pageSequence.getMainFlow());
-
-        if (pageSequence.getStaticContent("xsl-region-before") != null) {
-            refinement(pageSequence.getStaticContent("xsl-region-before"));
-        }
-        if (pageSequence.getStaticContent("xsl-region-after") != null) {
-            refinement(pageSequence.getStaticContent("xsl-region-after"));
-        }
-        if (pageSequence.getStaticContent("xsl-region-start") != null) {
-            refinement(pageSequence.getStaticContent("xsl-region-start"));
-        }
-        if (pageSequence.getStaticContent("xsl-region-end") != null) {
-            refinement(pageSequence.getStaticContent("xsl-region-end"));
-        }
-
-        super.endPageSequence(pageSequence);
-    }
-}
Index: src/java/org/apache/fop/layoutmgr/table/GridUnit.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/table/GridUnit.java	(revision 532293)
+++ src/java/org/apache/fop/layoutmgr/table/GridUnit.java	(working copy)
@@ -281,14 +281,8 @@
     public void resolveBorder(GridUnit other, int side, int resFlags) {
         CollapsingBorderModel borderModel = CollapsingBorderModel.getBorderModelFor(
                 getTable().getBorderCollapse());
-        if (effectiveBorders == null) {
-            effectiveBorders = new CommonBorderPaddingBackground();
-        }
-        effectiveBorders.setBorderInfo(borderModel.determineWinner(this, other,
-                        side, resFlags), side);
-        if (cell != null) {
-            effectiveBorders.setPadding(cell.getCommonBorderPaddingBackground());
-        }
+        BorderInfo bi = borderModel.determineWinner(this, other, side, resFlags);
+        effectiveBorders = CommonBorderPaddingBackground.getInstance(effectiveBorders, cell, bi, side);
         if (log.isDebugEnabled()) {
             log.debug(this + " resolved borders: "
                     + "before=" + effectiveBorders.getBorderBeforeWidth(false) + ", "
Index: src/java/org/apache/fop/datatypes/CompoundDatatype.java
===================================================================
--- src/java/org/apache/fop/datatypes/CompoundDatatype.java	(revision 532293)
+++ src/java/org/apache/fop/datatypes/CompoundDatatype.java	(working copy)
@@ -39,6 +39,7 @@
      * Returns a component of the compound datatype.
      * @param cmpId ID of the component
      * @return the value of the component
+     * @deprecated Fop is moving towards a system of immutable properties.
      */
     Property getComponent(int cmpId);
 }
Index: src/java/org/apache/fop/datatypes/LengthBase.java
===================================================================
--- src/java/org/apache/fop/datatypes/LengthBase.java	(revision 532293)
+++ src/java/org/apache/fop/datatypes/LengthBase.java	(working copy)
@@ -28,7 +28,7 @@
 import org.apache.fop.fo.flow.Character;
 import org.apache.fop.fo.flow.ExternalGraphic;
 import org.apache.fop.fo.flow.InstreamForeignObject;
-import org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager;
+import org.apache.fop.fo.properties.Property;
 
 /**
  * Models a length which can be used as a factor in a percentage length
@@ -71,15 +71,15 @@
     /**
      * The FO for which this property is to be calculated.
      */
-    protected /* final */ FObj fobj;
+    private final FObj fobj;
 
     /**
      * One of the defined types of LengthBase
      */
-    private /* final */ int baseType;
+    private final int baseType;
 
     /** For percentages based on other length properties */
-    private Length baseLength;
+    private final Length baseLength;
     
     /**
      * Constructor
@@ -101,6 +101,13 @@
         default:
             // TODO: pacify CheckStyle
             // throw new RuntimeException();
+            /**
+               This is the behaviour of the old code - probably not the desired
+               behaviour. Throwing IllegalArgumentException causes all sorts of
+               problems, including failure to process simple fos such as readme.fo
+               Not initializing anything gives null - RSW
+            */
+            baseLength = null;
             break;
         }
     }
@@ -134,6 +141,19 @@
         }
         return baseLen;
     }
+    
+    public int hashCode() {
+        return baseType + (baseLength==null ? 29 : baseLength.hashCode()) << 4;
+    }
+    
+    public boolean equals(Object obj) {
+        if (! (obj instanceof LengthBase))
+            return false;
+        LengthBase lb = (LengthBase)obj;
+        return lb.baseType == this.baseType &&
+            Property.eq(lb.baseLength, this.baseLength);
+    }
 
+
 }
 
Index: src/java/org/apache/fop/apps/FOUserAgent.java
===================================================================
--- src/java/org/apache/fop/apps/FOUserAgent.java	(revision 532293)
+++ src/java/org/apache/fop/apps/FOUserAgent.java	(working copy)
@@ -80,6 +80,7 @@
     private File outputFile = null;
     private Renderer rendererOverride = null;
     private FOEventHandler foEventHandlerOverride = null;
+    private boolean locatorEnabled = false; // TODO: Should be true by default (for error messages).
     
     /** Producer:  Metadata element for the system/software that produces
      * the document. (Some renderers can store this in the document.)
@@ -501,5 +502,24 @@
     public XMLHandlerRegistry getXMLHandlerRegistry() {
         return getFactory().getXMLHandlerRegistry();
     }
+    /**
+     * Enables use of SAXLocators to provide location information in error
+     * messages. Since this a somewhat expensive feature in terms of memory
+     * usage, many end user may which to disable it.
+     * @return true if context information should be stored on each node in the FO tree.
+     */
+    public void setLocatorEnabled(boolean en) {
+        locatorEnabled = en;
+    }
+
+    /**
+     * Are SAXLocators enabled?
+     * @see #setLocatorEnabled(boolean)
+     * @return true if context information should be stored on each node in the FO tree.
+     */
+    public boolean isLocatorEnabled() {
+        return locatorEnabled;
+    }
+
 }
 
Index: src/java/org/apache/fop/fo/properties/CommonHyphenation.java
===================================================================
--- src/java/org/apache/fop/fo/properties/CommonHyphenation.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/CommonHyphenation.java	(working copy)
@@ -29,46 +29,49 @@
  * Public "structure" allows direct member access.
  */
 public class CommonHyphenation {
+
+    private static final PropertyCache cache = new PropertyCache();
+
     /**
      * The "language" property.
      */
-    public String language;
+    public final String language;
 
     /**
      * The "country" property.
      */
-    public String country;
+    public final String country;
 
     /**
      * The "script" property.
      */
-    public String script;
+    public final String script;
 
     /**
      * The "hyphenate" property.
      */
-    public int hyphenate;
+    public final int hyphenate;
 
     /**
      * The "hyphenation-character" property.
      */
-    public char hyphenationCharacter;
+    public final char hyphenationCharacter;
 
     /**
      * The "hyphenation-push-character" property.
      */
-    public int hyphenationPushCharacterCount;
+    public final int hyphenationPushCharacterCount;
 
     /**
      * The "hyphenation-remain-character-count" property.
      */
-    public int hyphenationRemainCharacterCount;
+    public final int hyphenationRemainCharacterCount;
 
     /**
      * Create a CommonHyphenation object.
-     * @param pList The PropertyList with propery values.
+     * @param pList The PropertyList with property values.
      */
-    public CommonHyphenation(PropertyList pList) throws PropertyException {
+    private CommonHyphenation(PropertyList pList) throws PropertyException {
         language = pList.get(Constants.PR_LANGUAGE).getString();
         country = pList.get(Constants.PR_COUNTRY).getString();
         script = pList.get(Constants.PR_SCRIPT).getString();
@@ -81,4 +84,26 @@
 
     }
 
+    public int hashCode() {
+      return Property.hc(language) << 1 +
+        Property.hc(country) << 4 +
+        Property.hc(script) << 9 +
+        hyphenate;
+    }
+
+    public boolean equals(Object obj) {
+      CommonHyphenation c = (CommonHyphenation)obj;
+      return Property.eq(language, language) &&
+        Property.eq(country, country) &&
+        Property.eq(script, script) &&
+        hyphenate == c.hyphenate &&
+        hyphenationCharacter == c.hyphenationCharacter &&
+        hyphenationPushCharacterCount == c.hyphenationPushCharacterCount &&
+        hyphenationRemainCharacterCount == c.hyphenationRemainCharacterCount;
+    }
+
+    public static CommonHyphenation getInstance(PropertyList pList) throws PropertyException {
+        CommonHyphenation c = new CommonHyphenation(pList);
+        return (CommonHyphenation)cache.fetch(c);
+    }
 }
Index: src/java/org/apache/fop/fo/properties/CommonAccessibility.java
===================================================================
--- src/java/org/apache/fop/fo/properties/CommonAccessibility.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/CommonAccessibility.java	(working copy)
@@ -28,32 +28,44 @@
  * See Sec 7.4 of the XSL-FO Standard.
  * Public "structure" allows direct member access.
  */
-public class CommonAccessibility {
+public final class CommonAccessibility {
+
+    private static final PropertyCache cache = new PropertyCache();
+
     /**
      * The "source-doc" property.
      */
-    public String sourceDoc = null;
+    public final String sourceDoc;
 
     /**
      * The "role" property.
      */
-    public String role = null;
+    public final String role;
 
     /**
      * Create a CommonAbsolutePosition object.
      * @param pList The PropertyList with propery values.
      */
-    public CommonAccessibility(PropertyList pList) throws PropertyException {
-        sourceDoc = pList.get(Constants.PR_SOURCE_DOCUMENT).getString();
-        if ("none".equals(sourceDoc)) {
-            sourceDoc = null;
-        }
-        role = pList.get(Constants.PR_ROLE).getString();
-        if ("none".equals(role)) {
-            role = null;
-        }
-        
+    private CommonAccessibility(PropertyList pList) throws PropertyException {
+        String s = pList.get(Constants.PR_SOURCE_DOCUMENT).getString();
+        sourceDoc = ("none".equals(s)) ? null : s;
+        String r = pList.get(Constants.PR_ROLE).getString();
+        role = ("none".equals(r)) ? null : r;
     }
 
+    public int hashCode() {
+        return sourceDoc == null ? 0 : sourceDoc.hashCode() +
+            role == null ? 0 : role.hashCode() << 1;
+    }
 
+    public boolean equals(Object obj) {
+        CommonAccessibility ca = (CommonAccessibility)obj;        
+        return Property.eq(ca.sourceDoc, this.sourceDoc) &&
+            Property.eq(ca.role, this.role);
+    }
+
+    public static CommonAccessibility getInstance(PropertyList pList) throws PropertyException {
+        CommonAccessibility ca = new CommonAccessibility(pList);
+        return (CommonAccessibility)cache.fetch(ca);
+    }
 }
Index: src/java/org/apache/fop/fo/properties/BorderWidthPropertyMaker.java
===================================================================
--- src/java/org/apache/fop/fo/properties/BorderWidthPropertyMaker.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/BorderWidthPropertyMaker.java	(working copy)
@@ -63,7 +63,7 @@
         // Calculate the values as described in 7.7.20.
         Property style = propertyList.get(borderStyleId);
         if (style.getEnum() == Constants.EN_NONE) {
-            return new FixedLength(0);
+            return FixedLength.getInstance(0);
         }
         return p;
     }
Index: src/java/org/apache/fop/fo/properties/LengthRangeProperty.java
===================================================================
--- src/java/org/apache/fop/fo/properties/LengthRangeProperty.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/LengthRangeProperty.java	(working copy)
@@ -84,7 +84,7 @@
                         log.warn(FObj.decorateWithContextInfo(
                                 "Replaced negative value (" + len + ") for " + getName()
                                 + " with 0mpt", fo));
-                        p = new FixedLength(0);
+                        p = FixedLength.getInstance(0);
                     }
                 }
             }
@@ -106,8 +106,7 @@
                     if (isNegativeLength(len)) {
                         log.warn("Replaced negative value (" + len + ") for " + getName()
                                 + " with 0mpt");
-                        val.setComponent(subpropertyId,
-                                new FixedLength(0), false);
+                        val.setComponent(subpropertyId, FixedLength.getInstance(0), false);
                         return baseProperty;
                     }
                 }
@@ -136,6 +135,7 @@
 
     /**
      * @see org.apache.fop.datatypes.CompoundDatatype#getComponent(int)
+     * @deprecated LengthRangeProperty should be immutable
      */
     public Property getComponent(int cmpId) {
         if (cmpId == CP_MINIMUM) {
@@ -155,6 +155,7 @@
      * LengthRange.
      * @param bIsDefault If true, this is set as a "default" value
      * and not a user-specified explicit value.
+     * @deprecated LengthRangeProperty should be immutable
      */
     protected void setMinimum(Property minimum, boolean bIsDefault) {
         this.minimum = minimum;
@@ -170,6 +171,7 @@
      * @param max A Length value specifying the maximum value for this
      * @param bIsDefault If true, this is set as a "default" value
      * and not a user-specified explicit value.
+     * @deprecated LengthRangeProperty should be immutable
      */
     protected void setMaximum(Property max, boolean bIsDefault) {
         maximum = max;
@@ -185,6 +187,7 @@
      * @param opt A Length value specifying the optimum value for this
      * @param bIsDefault If true, this is set as a "default" value
      * and not a user-specified explicit value.
+     * @deprecated LengthRangeProperty should be immutable
      */
     protected void setOptimum(Property opt, boolean bIsDefault) {
         optimum = opt;
@@ -298,5 +301,21 @@
     public Object getObject() {
         return this;
     }
-
+    
+    public int hashCode() {
+        return bfSet + minimum.hashCode() << 4 +
+            optimum.hashCode() << 8 + maximum.hashCode() << 12;
+    }
+    
+    public boolean equals(Object obj) {
+        if (! (obj instanceof LengthRangeProperty))
+            return false;
+        LengthRangeProperty lrp = (LengthRangeProperty)obj;
+        return this.bfSet == lrp.bfSet &&
+            this.consistent == lrp.consistent &&
+            Property.eq(this.minimum, lrp.minimum) &&
+            Property.eq(this.optimum, lrp.optimum) &&
+            Property.eq(this.maximum, lrp.maximum);
+    }
+    
 }
Index: src/java/org/apache/fop/fo/properties/EnumProperty.java
===================================================================
--- src/java/org/apache/fop/fo/properties/EnumProperty.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/EnumProperty.java	(working copy)
@@ -65,7 +65,7 @@
         }
     }
 
-    private static final Map propertyCache = new WeakHashMap();
+    private static final PropertyCache cache = new PropertyCache();
 
     private final int value;
     private final String text;
@@ -80,14 +80,7 @@
     }
 
     public static EnumProperty getInstance(int explicitValue, String text) {
-        EnumProperty ep = new EnumProperty(explicitValue, text);
-        EnumProperty cacheEntry = (EnumProperty)propertyCache.get(ep);
-        if (cacheEntry == null) {
-            propertyCache.put(ep, ep);
-            return ep;
-        } else {
-            return cacheEntry;
-        }
+        return (EnumProperty)cache.fetch(new EnumProperty(explicitValue, text));
     }
 
     /**
@@ -110,10 +103,8 @@
     public boolean equals(Object obj) {
         if (obj instanceof EnumProperty) {
             EnumProperty ep = (EnumProperty)obj;
-            return (ep.value == this.value) 
-                && ((ep.text == this.text)
-                    || (ep.text != null
-                        && ep.text.equals(this.text)));
+            return this.value == ep.value &&
+              Property.eq(this.text, ep.text);
         } else {
             return false;
         }
Index: src/java/org/apache/fop/fo/properties/CommonAbsolutePosition.java
===================================================================
--- src/java/org/apache/fop/fo/properties/CommonAbsolutePosition.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/CommonAbsolutePosition.java	(working copy)
@@ -30,30 +30,33 @@
  * Public "structure" allows direct member access.
  */
 public class CommonAbsolutePosition {
+
+    private static final PropertyCache cache = new PropertyCache();
+
     /**
      * The "absolute-position" property.
      */
-    public int absolutePosition;
+    public final int absolutePosition;
 
     /**
      * The "top" property.
      */
-    public Length top;
+    public final Length top;
 
     /**
      * The "right" property.
      */
-    public Length right;
+    public final Length right;
     
     /**
      * The "bottom" property.
      */
-    public Length bottom;
+    public final Length bottom;
     
     /**
      * The "left" property.
      */
-    public Length left;
+    public final Length left;
 
     /**
      * Create a CommonAbsolutePosition object.
@@ -82,4 +85,27 @@
         sb.append("}");
         return sb.toString();
     }
+
+    public int hashCode() {
+      return absolutePosition + 
+        Property.hc(top) << 2 +
+        Property.hc(right) << 4 +
+        Property.hc(bottom) << 6 +
+        Property.hc(left) << 8;
+    }
+
+    public boolean equals(Object obj) {
+        CommonAbsolutePosition cap = (CommonAbsolutePosition)obj;        
+        return cap.absolutePosition == absolutePosition &&
+          Property.eq(cap.top, top) &&
+          Property.eq(cap.right, right) &&
+          Property.eq(cap.bottom, bottom) &&
+          Property.eq(cap.left, left);
+    }
+
+    public static CommonAbsolutePosition getInstance(PropertyList pList) throws PropertyException {
+        CommonAbsolutePosition cap = new CommonAbsolutePosition(pList);
+        return (CommonAbsolutePosition)cache.fetch(cap);
+    }
+
 }
Index: src/java/org/apache/fop/fo/properties/EnumNumber.java
===================================================================
--- src/java/org/apache/fop/fo/properties/EnumNumber.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/EnumNumber.java	(working copy)
@@ -27,7 +27,7 @@
  */
 public class EnumNumber extends NumberProperty {
 
-    private static final Map cache = new WeakHashMap();
+    private static final PropertyCache cache = new PropertyCache();
 
     private final EnumProperty enumProperty;
     
@@ -37,12 +37,8 @@
     }
 
     public static EnumNumber getInstance(Property enumProperty) {
-        EnumNumber en = (EnumNumber)cache.get(enumProperty);
-        if (en == null) {
-            en = new EnumNumber((EnumProperty)enumProperty);
-            cache.put(enumProperty, en);
-        }
-        return en;
+        EnumNumber en = new EnumNumber((EnumProperty)enumProperty);
+        return (EnumNumber)cache.fetch(en);
     }
 
     public int getEnum() {
@@ -81,5 +77,19 @@
         return enumProperty.getObject();
     }
 
+    /**
+     * @see java.lang.Object#equals(Object)
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof EnumNumber) {
+            EnumNumber ep = (EnumNumber)obj;
+            return Property.eq(this.enumProperty, ep.enumProperty);
+        } else {
+            return false;
+        }
+    }
 
+    public int hashCode() {
+        return enumProperty.hashCode();
+    }
 }
Index: src/java/org/apache/fop/fo/properties/Property.java
===================================================================
--- src/java/org/apache/fop/fo/properties/Property.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/Property.java	(working copy)
@@ -199,4 +199,31 @@
         }
         return null;
     }
+
+    /**
+       Utility method which returns true iff obj1.equals(obj2)
+       or obj1 and obj2 are both null. Performs a deep equality
+       comparison if obj1 and obj2 are both arrays.
+    */
+    public static final boolean eq(Object obj1, Object obj2) {
+        if (obj1 instanceof Object[]) {
+            if (obj1==null && obj2==null) return true;
+            if (obj1==null || obj2==null) return false;
+            if (! (obj1 instanceof Object[])) return false;
+            Object[] arr1 = (Object[])obj1;
+            Object[] arr2 = (Object[])obj2;
+            if (arr1.length != arr2.length) return false;
+            for (int i = 0; i < arr1.length; i++)
+                if (!eq(arr1[i], arr2[i]))
+                    return false;
+            return true;
+        } else {
+            return (obj1 == obj2) ||
+                (obj1 != null && obj2 != null && obj1.equals(obj2));
+        }
+    }
+
+    static final int hc(Object obj) {
+        return obj == null ? 0 : obj.hashCode();
+    }
 }
Index: src/java/org/apache/fop/fo/properties/CondLengthProperty.java
===================================================================
--- src/java/org/apache/fop/fo/properties/CondLengthProperty.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/CondLengthProperty.java	(working copy)
@@ -162,4 +162,14 @@
         return this;
     }
 
+    public int hashCode() {
+        return length.hashCode() + conditionality.hashCode();
+    }
+
+    public boolean equals(Object obj) {
+        if (! (obj instanceof CondLengthProperty)) return false;
+        CondLengthProperty c = (CondLengthProperty)obj;
+        return Property.eq(length, c.length) &&
+            Property.eq(conditionality, c.conditionality);
+    }
 }
Index: src/java/org/apache/fop/fo/properties/NumberProperty.java
===================================================================
--- src/java/org/apache/fop/fo/properties/NumberProperty.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/NumberProperty.java	(working copy)
@@ -69,7 +69,7 @@
 
     }
 
-    private Number number;
+    private final Number number;
 
     /**
      * Constructor for Number input
@@ -172,7 +172,7 @@
     /** @see org.apache.fop.fo.properties.Property#getLength() */
     public Length getLength() {
         //Assume pixels (like in HTML) when there's no unit
-        return new FixedLength(getNumericValue(), "px");
+        return FixedLength.getInstance(getNumericValue(), "px");
     }
 
     /**
@@ -187,4 +187,14 @@
         return Color.black;
     }
 
+    public int hashCode() {
+        return number.hashCode();
+    }
+
+    public boolean equals(Object obj) {
+        if (! (obj instanceof NumberProperty))
+            return false;
+        NumberProperty n = (NumberProperty)obj;
+        return Property.eq(number, n.number);
+    }
 }
Index: src/java/org/apache/fop/fo/properties/SpaceProperty.java
===================================================================
--- src/java/org/apache/fop/fo/properties/SpaceProperty.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/SpaceProperty.java	(working copy)
@@ -167,4 +167,13 @@
         return this;
     }
 
+    public boolean equals(Object obj) {
+        if (! (obj instanceof SpaceProperty))
+          return false;
+        SpaceProperty c = (SpaceProperty)obj;
+        return super.equals(obj) &&
+          Property.eq(precedence, c.precedence) &&
+          Property.eq(conditionality, c.conditionality);
+    }
+
 }
Index: src/java/org/apache/fop/fo/properties/FixedLength.java
===================================================================
--- src/java/org/apache/fop/fo/properties/FixedLength.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/FixedLength.java	(working copy)
@@ -25,31 +25,45 @@
  * An absolute length quantity in XSL
  */
 public class FixedLength extends LengthProperty {
+
+    private static final PropertyCache cache = new PropertyCache();
+
     private int millipoints;
 
+    private FixedLength(int millis) {
+        millipoints = millis;
+    }
+
     /**
-     * Set the length given
+     * Obtain an instance given a number of units and a font size.
      * @param numRelUnits the number of relative units
      * @param iCurFontSize the current font size in base units.
+     * @return A new or previously cached instance of FixedLength
      */
-    public FixedLength(double numRelUnits, int iCurFontSize) {
-        millipoints = (int) (numRelUnits * (double)iCurFontSize);
+    public static FixedLength getInstance(double numRelUnits, int iCurFontSize) {
+        FixedLength fl = new FixedLength((int) (numRelUnits * (double)iCurFontSize));
+        return (FixedLength)cache.fetch(fl);
     }
 
     /**
-     * Set the length given a number of units and a unit name.
+     * Obtain an instance given a number of units and a unit name.
      * @param numUnits quantity of input units
      * @param units input unit specifier (in, cm, etc.)
+     * @return A new or previously cached instance of FixedLength
      */
-    public FixedLength(double numUnits, String units) {
-        convert(numUnits, units);
+    public static FixedLength getInstance(double numUnits, String units) {
+        FixedLength fl = new FixedLength(convert(numUnits, units));
+        return (FixedLength)cache.fetch(fl);
     }
 
     /**
+     * Obtain an instance given a number of units.
      * @param baseUnits the length as a number of base units (millipoints)
+     * @return A new or previously cached instance of FixedLength
      */
-    public FixedLength(int baseUnits) {
-        millipoints = baseUnits;
+    public static FixedLength getInstance(int baseUnits) {
+        FixedLength fl = new FixedLength(baseUnits);
+        return (FixedLength)cache.fetch(fl);
     }
 
     /**
@@ -58,7 +72,7 @@
      * @param dvalue quantity of input units
      * @param unit input unit specifier (in, cm, etc.)
      */
-    protected void convert(double dvalue, String unit) {
+    private static int convert(double dvalue, String unit) {
         // TODO: the whole routine smells fishy.
 
         int assumedResolution = 1;    // points/pixel = 72dpi
@@ -90,9 +104,9 @@
             log.error("Unknown length unit '" + unit + "'");
         }
         if (unit.equals("mpt")) {
-            millipoints = (int)dvalue;
+            return (int)dvalue;
         } else {
-            millipoints = (int)(dvalue * 1000);
+            return (int)(dvalue * 1000);
         }
     }
 
@@ -139,5 +153,15 @@
         return millipoints + "mpt";
     }
 
+    public boolean equals(Object obj) {
+        if (!(obj instanceof FixedLength))
+            return false;
+        FixedLength fl = (FixedLength)obj;
+        return millipoints == fl.millipoints;
+    }
+
+    public int hashCode() {
+        return millipoints;
+    }
 }
 
Index: src/java/org/apache/fop/fo/properties/CommonMarginBlock.java
===================================================================
--- src/java/org/apache/fop/fo/properties/CommonMarginBlock.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/CommonMarginBlock.java	(working copy)
@@ -30,51 +30,59 @@
  * Public "structure" allows direct member access.
  */
 public class CommonMarginBlock {
+
+    private static final PropertyCache cache = new PropertyCache();
+
     /**
      * The "margin-top" property.
      */
-    public Length marginTop;
+    public final Length marginTop;
 
     /**
      * The "margin-bottom" property.
      */
-    public Length marginBottom;
+    public final Length marginBottom;
 
     /**
      * The "margin-left" property.
      */
-    public Length marginLeft;
+    public final Length marginLeft;
 
     /**
      * The "margin-right" property.
      */
-    public Length marginRight;
+    public final Length marginRight;
 
     /**
      * The "space-before" property.
      */
-    public SpaceProperty spaceBefore;
+    public final SpaceProperty spaceBefore;
 
     /**
      * The "space-after" property.
      */
-    public SpaceProperty spaceAfter;
+    public final SpaceProperty spaceAfter;
 
     /**
      * The "start-indent" property.
      */
-    public Length startIndent;
+    public final Length startIndent;
 
     /**
      * The "end-indent" property.
      */
-    public Length endIndent;
+    public final Length endIndent;
 
+    public static final CommonMarginBlock getInstance(PropertyList pList) throws PropertyException {
+        CommonMarginBlock c = new CommonMarginBlock(pList);
+        return (CommonMarginBlock)cache.fetch(c);
+    }
+
     /**
      * Create a CommonMarginBlock object.
      * @param pList The PropertyList with propery values.
      */
-    public CommonMarginBlock(PropertyList pList) throws PropertyException {
+    private CommonMarginBlock(PropertyList pList) throws PropertyException {
         marginTop = pList.get(Constants.PR_MARGIN_TOP).getLength();
         marginBottom = pList.get(Constants.PR_MARGIN_BOTTOM).getLength();
         marginLeft = pList.get(Constants.PR_MARGIN_LEFT).getLength();
@@ -98,5 +106,30 @@
             + "Indents (start, end): ("
             + startIndent + ", " + endIndent + ")\n";
     }
+
+    public int hashCode() {
+        return marginTop.hashCode() << 1 +
+            marginBottom.hashCode() << 2 +
+            marginLeft.hashCode() << 4 +
+            marginRight.hashCode() << 6 +
+            spaceBefore.hashCode() << 8 +
+            spaceAfter.hashCode() << 10 +
+            startIndent.hashCode() << 12 +
+            endIndent.hashCode() << 14;
+    }
+
+    public boolean equals(Object obj) {
+        if (!(obj instanceof CommonMarginBlock))
+            return false;
+        CommonMarginBlock cmb = (CommonMarginBlock)obj;
+        return Property.eq(this.marginTop, cmb.marginTop) &&
+            Property.eq(this.marginBottom, cmb.marginBottom) &&
+            Property.eq(this.marginLeft, cmb.marginLeft) &&
+            Property.eq(this.marginRight, cmb.marginRight) &&
+            Property.eq(this.spaceBefore, cmb.spaceBefore) &&
+            Property.eq(this.spaceAfter, cmb.spaceAfter) &&
+            Property.eq(this.startIndent, cmb.startIndent) &&
+            Property.eq(this.endIndent, cmb.endIndent);
+    }
     
 }
Index: src/java/org/apache/fop/fo/properties/PercentLength.java
===================================================================
--- src/java/org/apache/fop/fo/properties/PercentLength.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/PercentLength.java	(working copy)
@@ -32,15 +32,13 @@
      * The percentage itself, expressed as a decimal value, e.g. for 95%, set
      * the value to .95
      */
-    private double factor;
+    private final double factor;
 
     /**
      * A PercentBase implementation that contains the base length to which the
      * {@link #factor} should be applied to compute the actual length
      */
-    private PercentBase lbase = null;
-    
-    private double resolvedValue;
+    private final PercentBase lbase;
 
     /**
      * Main constructor. Construct an object based on a factor (the percent,
@@ -92,8 +90,7 @@
      */
     public double getNumericValue(PercentBaseContext context) {
         try {
-            resolvedValue = factor * lbase.getBaseLength(context);
-            return resolvedValue;
+            return factor * lbase.getBaseLength(context);
         } catch (PropertyException exc) {
             log.error(exc);
             return 0;
@@ -123,4 +120,17 @@
         return (new Double(factor * 100.0).toString()) + "%";
     }
 
+    public int hashCode() {
+      return lbase.hashCode();
+    }
+    
+    public boolean equals(Object obj) {
+        if (! (obj instanceof PercentLength))
+            return false;
+        PercentLength pl = (PercentLength)obj;
+        return pl.factor == this.factor &&
+          Property.eq(pl.lbase, this.lbase);
+    }
+
+
 }
Index: src/java/org/apache/fop/fo/properties/PropertyMaker.java
===================================================================
--- src/java/org/apache/fop/fo/properties/PropertyMaker.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/PropertyMaker.java	(working copy)
@@ -68,7 +68,7 @@
     /**
      * @return the name of the property for this Maker
      */
-    public int getPropId() {
+    public final int getPropId() {
         return propId;
     }
 
Index: src/java/org/apache/fop/fo/properties/IndentPropertyMaker.java
===================================================================
--- src/java/org/apache/fop/fo/properties/IndentPropertyMaker.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/IndentPropertyMaker.java	(working copy)
@@ -108,7 +108,7 @@
             //Margin is used
             Numeric margin = propertyList.get(marginProp).getNumeric();
             
-            Numeric v = new FixedLength(0);
+            Numeric v = FixedLength.getInstance(0);
             if (!propertyList.getFObj().generatesReferenceAreas()) {
                 // The inherited_value_of([start|end]-indent)
                 v = NumericOp.addition(v, propertyList.getInherited(baseMaker.propId).getNumeric());
@@ -173,7 +173,7 @@
                 if (isInherited(propertyList) || !marginNearest) {
                     return null;
                 } else {
-                    return new FixedLength(0);
+                    return FixedLength.getInstance(0);
                 }
             } else {
                 return indent;
@@ -182,7 +182,7 @@
             //Margin is used
             Numeric margin = propertyList.get(marginProp).getNumeric();
             
-            Numeric v = new FixedLength(0);
+            Numeric v = FixedLength.getInstance(0);
             if (isInherited(propertyList)) {
                 // The inherited_value_of([start|end]-indent)
                 v = NumericOp.addition(v, propertyList.getInherited(baseMaker.propId).getNumeric());
Index: src/java/org/apache/fop/fo/properties/PropertyCache.java
===================================================================
--- src/java/org/apache/fop/fo/properties/PropertyCache.java	(revision 0)
+++ src/java/org/apache/fop/fo/properties/PropertyCache.java	(revision 0)
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo.properties;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+   Thin wrapper around a HashMap to implement the property caching idiom
+   in which a new Property instance is created then tested against cached
+   instances created previously. If an existing property is found, this is
+   retained and the newly created one is instantly eligible for garbage
+   collection.
+*/
+public class PropertyCache {
+
+    private Map cache = new WeakHashMap();
+
+    /**
+       Checks if the given object is present in the cache - if so, returns
+       a reference to the cached value. Otherwise the given object is added
+       to the cache and returned.
+    */
+    public synchronized Object fetch(Object obj) {
+        Object cacheEntry = cache.get(obj);
+        if (cacheEntry == null) {
+            cache.put(obj, obj);
+            return obj;
+        } else {
+            return cacheEntry;
+        }
+    }
+}
Index: src/java/org/apache/fop/fo/properties/CommonRelativePosition.java
===================================================================
--- src/java/org/apache/fop/fo/properties/CommonRelativePosition.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/CommonRelativePosition.java	(working copy)
@@ -30,30 +30,33 @@
  * Public "structure" allows direct member access.
  */
 public class CommonRelativePosition {
+
+    private static final PropertyCache cache = new PropertyCache();
+
     /**
      * The "relative-position" property.
      */
-    public int relativePosition;
+    public final int relativePosition;
     
     /**
      * The "top" property.
      */
-    public Length top;
+    public final Length top;
 
     /**
      * The "right" property.
      */
-    public Length right;
+    public final Length right;
     
     /**
      * The "bottom" property.
      */
-    public Length bottom;
+    public final Length bottom;
     
     /**
      * The "left" property.
      */
-    public Length left;
+    public final Length left;
 
     /**
      * Create a CommonRelativePosition object.
@@ -67,4 +70,25 @@
         right = pList.get(Constants.PR_RIGHT).getLength();      
     }
 
+    public int hashCode() {
+      return relativePosition + 
+        Property.hc(top) << 2 +
+        Property.hc(right) << 4 +
+        Property.hc(bottom) << 6 +
+        Property.hc(left) << 8;
+    }
+
+    public boolean equals(Object obj) {
+        CommonRelativePosition c = (CommonRelativePosition)obj;        
+        return c.relativePosition == relativePosition &&
+          Property.eq(c.top, top) &&
+          Property.eq(c.right, right) &&
+          Property.eq(c.bottom, bottom) &&
+          Property.eq(c.left, left);
+    }
+
+    public static CommonRelativePosition getInstance(PropertyList pList) throws PropertyException {
+        CommonRelativePosition c = new CommonRelativePosition(pList);
+        return (CommonRelativePosition)cache.fetch(c);
+    }
 }
Index: src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
===================================================================
--- src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java	(working copy)
@@ -28,6 +28,7 @@
 import org.apache.fop.fo.FObj;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.fo.flow.TableCell;
 import org.apache.fop.image.FopImage;
 import org.apache.fop.image.ImageFactory;
 
@@ -36,40 +37,39 @@
  * See Sec. 7.7 of the XSL-FO Standard.
  */
 public class CommonBorderPaddingBackground {
+
+    private static final PropertyCache cache = new PropertyCache();
+
     /**
      * 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 FopImage fopimage;
-    
-    
     /** the "before" edge */ 
     public static final int BEFORE = 0;
     /** the "after" edge */ 
@@ -123,16 +123,71 @@
             sb.append("}");
             return sb.toString();
         }
+
+        public int hashCode() {
+            return mStyle + mColor.hashCode() << 4 + mWidth.hashCode() << 7;
+        }
+
+        public boolean equals(Object obj) {
+            if (!( obj instanceof BorderInfo))
+                return false;
+            BorderInfo b = (BorderInfo)obj;
+            return this.mStyle == b.mStyle &&
+                Property.eq(this.mColor, b.mColor) &&
+                Property.eq(this.mWidth, b.mWidth);
+        }
     }
+    
+    private final FopImage fopimage;
 
-    private BorderInfo[] borderInfo = new BorderInfo[4];
-    private CondLengthProperty[] padding = new CondLengthProperty[4];
+    private final BorderInfo[] borderInfo = new BorderInfo[4];
 
+    /** 
+        Padding lengths, indexed by BEFORE, AFTER, START, END
+    */
+    private CondLengthProperty[] padding = new CondLengthProperty[4]; // TODO: Should be final
+
     /**
-     * Construct a CommonBorderPaddingBackground object.
+       Returns a new  CommonBorderPaddingBackground instance with appropriate changes
+       made to border and padding.
+       @param src The original CBPB whose properties to take.
+       @param cell 
+    */
+    public static final CommonBorderPaddingBackground getInstance(CommonBorderPaddingBackground src,
+                                                                  TableCell cell,
+                                                                  BorderInfo bi, int side) {
+        if (bi==null && cell==null) {
+            return src;
+        }
+        CommonBorderPaddingBackground nc = new CommonBorderPaddingBackground(src, cell, bi, side);
+        return (CommonBorderPaddingBackground)cache.fetch(nc);
+    }
+
+    public static final CommonBorderPaddingBackground getInstance(PropertyList pList) throws PropertyException {
+        CommonBorderPaddingBackground c = new CommonBorderPaddingBackground(pList, pList.getFObj());
+        return (CommonBorderPaddingBackground)cache.fetch(c);
+    }
+
+    /**
+     * See the above get instance() method.
      */
-    public CommonBorderPaddingBackground() {
-        
+    private CommonBorderPaddingBackground(CommonBorderPaddingBackground src, TableCell cell,
+                                          BorderInfo bi, int side) {
+        this.backgroundAttachment = src.backgroundAttachment;
+        this.backgroundColor = src.backgroundColor;
+        this.backgroundImage = src.backgroundImage;
+        this.backgroundRepeat = src.backgroundRepeat;
+        this.backgroundPositionHorizontal = src.backgroundPositionHorizontal;
+        this.backgroundPositionVertical = src.backgroundPositionVertical;
+        this.fopimage = src.fopimage;
+        if (cell!=null) {
+            CondLengthProperty[] srcPadding = cell.getCommonBorderPaddingBackground().padding;
+            for (int i = 0; i < padding.length ; i++)
+                this.padding[i] = srcPadding[i];
+        }
+        if (bi!=null) {
+            this.borderInfo[side] = bi;
+        }
     }
     
     /**
@@ -141,19 +196,22 @@
      * @param fobj The FO to create this instance for.
      * @throws PropertyException if there's an error while binding the properties
      */
-    public CommonBorderPaddingBackground(PropertyList pList, FObj fobj) throws PropertyException {
+    private CommonBorderPaddingBackground(PropertyList pList, FObj fobj) 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(
                 fobj == null ? null : fobj.getUserAgent());
-        if (backgroundColor.getAlpha() == 0) {
-            backgroundColor = null;
-        }
+        backgroundColor = bc.getAlpha() == 0 ? null : bc;
 
-        backgroundImage = pList.get(Constants.PR_BACKGROUND_IMAGE).getString();
-        if (backgroundImage == null || "none".equals(backgroundImage)) {
+        String bi = pList.get(Constants.PR_BACKGROUND_IMAGE).getString();
+        if (bi == null || "none".equals(bi)) {
             backgroundImage = null;
+            backgroundRepeat = 0;
+            backgroundPositionHorizontal = null;
+            backgroundPositionVertical = null;
+            fopimage = null;
         } else {
+            backgroundImage = bi;
             backgroundRepeat = pList.get(Constants.PR_BACKGROUND_REPEAT).getEnum();
             backgroundPositionHorizontal = pList.get(
                     Constants.PR_BACKGROUND_POSITION_HORIZONTAL).getLength();
@@ -220,6 +278,7 @@
      * Sets a border.
      * @param info the border information
      * @param side the side to apply the info to
+     * @deprecated CommonBorderPaddingBackground should be immutable.
      */
     public void setBorderInfo(BorderInfo info, int side) {
         this.borderInfo[side] = info;
@@ -232,10 +291,11 @@
     public BorderInfo getBorderInfo(int side) {
         return this.borderInfo[side];
     }
-    
+
     /**
      * Set padding.
      * @param source the padding info to copy from
+     * @deprecated CommonBorderPaddingBackground should be immutable.
      */
     public void setPadding(CommonBorderPaddingBackground source) {
         this.padding = source.padding;
@@ -405,4 +465,32 @@
         return (borderInfo[BEFORE] != null || borderInfo[AFTER] != null
                 || borderInfo[START] != null || borderInfo[END] != null);
     }
+
+    public int hashCode() {
+        return Property.hc(backgroundColor) << 1 +
+            Property.hc(backgroundImage) << 3 +
+            backgroundRepeat << 5 +
+            Property.hc(backgroundPositionHorizontal) << 7 +
+            Property.hc(backgroundPositionVertical);
+    }
+
+    public boolean equals(Object obj) {
+        if (!(obj instanceof CommonBorderPaddingBackground))
+            return false;
+        CommonBorderPaddingBackground c = (CommonBorderPaddingBackground)obj;
+        return backgroundAttachment == c.backgroundAttachment &&
+            backgroundRepeat == c.backgroundRepeat &&
+            Property.eq(backgroundColor, c.backgroundColor) &&
+            Property.eq(backgroundImage, c.backgroundImage) &&
+            Property.eq(backgroundPositionHorizontal, c.backgroundPositionHorizontal) &&
+            Property.eq(backgroundPositionVertical, c.backgroundPositionVertical) &&
+            Property.eq(padding[BEFORE], c.padding[BEFORE]) &&
+            Property.eq(padding[AFTER], c.padding[AFTER]) &&
+            Property.eq(padding[START], c.padding[START]) &&
+            Property.eq(padding[END], c.padding[END]) &&
+            Property.eq(borderInfo, c.borderInfo) &&
+            (fopimage == c.fopimage ||
+             (fopimage!=null &&
+              fopimage.getOriginalURI().equals(c.fopimage.getOriginalURI())));
+    }
 }
Index: src/java/org/apache/fop/fo/properties/CommonAural.java
===================================================================
--- src/java/org/apache/fop/fo/properties/CommonAural.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/CommonAural.java	(working copy)
@@ -121,6 +121,13 @@
      * Create a CommonAbsolutePosition object.
      * @param pList The PropertyList with propery values.
      */
-    public CommonAural(PropertyList pList) {
+    private CommonAural(PropertyList pList) {
     }
+
+    /**
+       Placeholder. See CommonAccessibility for the correct instantiation idiom.
+    */
+    public static CommonAural getInstance(PropertyList pList) {
+        return null;
+    }
 }
Index: src/java/org/apache/fop/fo/properties/CommonFont.java
===================================================================
--- src/java/org/apache/fop/fo/properties/CommonFont.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/CommonFont.java	(working copy)
@@ -38,45 +38,47 @@
  */
 public class CommonFont {
 
+    private static final PropertyCache cache = new PropertyCache();
+
     /**
      * The "font-family" property.
      */
-    private String[] fontFamily;
+    private final String[] fontFamily;
 
     /**
      * The "font-selection-strategy" property.
      */
-    public int fontSelectionStrategy;
+    public final int fontSelectionStrategy;
 
     /**
      * The "font-size" property.
      */
-    public Length fontSize;
+    public final Length fontSize;
 
     /**
      * The "font-stretch" property.
      */
-    public int fontStretch;
+    public final int fontStretch;
 
     /**
      * The "font-size-adjust" property.
      */
-    public Numeric fontSizeAdjust;
+    public final Numeric fontSizeAdjust;
 
     /**
      * The "font-style" property.
      */
-    public int fontStyle;
+    public final int fontStyle;
 
     /**
      * The "font-variant" property.
      */
-    public int fontVariant;
+    public final int fontVariant;
 
     /**
      * The "font-weight" property.
      */
-    public int fontWeight;
+    public final int fontWeight;
 
     private Font fontState;
 
@@ -84,15 +86,17 @@
      * Create a CommonFont object.
      * @param pList The PropertyList to get properties from.
      */
-    public CommonFont(PropertyList pList) throws PropertyException {
+    private CommonFont(PropertyList pList) throws PropertyException {
         List lst = pList.get(Constants.PR_FONT_FAMILY).getList();
-        fontFamily = new String[lst.size()];
-        for (int i = 0, c = lst.size(); i < c; i++) {
-            fontFamily[i] = ((Property)lst.get(i)).getString();
-        }
-        if (fontFamily.length == 0) {
+        int lstSize = lst.size();
+        if (lstSize == 0) {
             //Shouldn't happen, but we never know.
             fontFamily = new String[] {"any"};
+        } else {
+          fontFamily = new String[lstSize];
+          for (int i = 0, c = lstSize; i < c; i++) {
+            fontFamily[i] = ((Property)lst.get(i)).getString();
+          }
         }
         fontSelectionStrategy = pList.get(Constants.PR_FONT_SELECTION_STRATEGY).getEnum();
         fontSize = pList.get(Constants.PR_FONT_SIZE).getLength();
@@ -103,6 +107,11 @@
         fontWeight = pList.get(Constants.PR_FONT_WEIGHT).getEnum();
     }
 
+    public static CommonFont getInstance(PropertyList pList) throws PropertyException {
+        CommonFont cf = new CommonFont(pList);
+        return (CommonFont)cache.fetch(cf);
+    }
+
     /** @return the first font-family name in the list */
     public String getFirstFontFamily() {
         return this.fontFamily[0];
@@ -114,15 +123,6 @@
     }
     
     /**
-     * Overrides the font-family.
-     * @param value the new font-family
-     */
-    public void overrideFontFamily(String value) {
-        this.fontFamily = new String[] {value};
-        
-    }
-    
-    /**
      * Create and return a Font object based on the properties. 
      * 
      * @param fontInfo
@@ -175,4 +175,22 @@
         return fontState;
     }
 
+    public int hashCode() {
+        return fontStretch + fontStyle + fontVariant + fontWeight;
+    }
+
+    public boolean equals(Object obj) {
+        if (! (obj instanceof CommonFont))
+            return false;
+        CommonFont cf = (CommonFont)obj;
+        return fontSelectionStrategy == cf.fontSelectionStrategy &&
+            fontStretch == cf.fontStretch &&
+            fontStyle == cf.fontStyle &&
+            fontVariant == cf.fontVariant &&
+            fontWeight == cf.fontWeight &&
+            fontFamily.length == cf.fontFamily.length &&
+            Property.eq(fontSize,  cf.fontSize) &&
+            Property.eq(fontSizeAdjust, cf.fontSizeAdjust) &&
+            Property.eq(fontFamily, cf.fontFamily);
+    }
 }
Index: src/java/org/apache/fop/fo/properties/ColorProperty.java
===================================================================
--- src/java/org/apache/fop/fo/properties/ColorProperty.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/ColorProperty.java	(working copy)
@@ -138,5 +138,22 @@
     public Object getObject() {
         return this;
     }
+
+    /**
+     * @see java.lang.Object#equals(Object)
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof ColorProperty) {
+            ColorProperty cp = (ColorProperty)obj;
+            return Property.eq(cp.color, this.color);
+        } else {
+            return false;
+        }
+    }
+
+    public int hashCode() {
+        return color.hashCode();
+    }
+
 }
 
Index: src/java/org/apache/fop/fo/properties/LengthProperty.java
===================================================================
--- src/java/org/apache/fop/fo/properties/LengthProperty.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/LengthProperty.java	(working copy)
@@ -59,7 +59,7 @@
             }
             if (p instanceof NumberProperty) {
                 //Assume pixels (like in HTML) when there's no unit
-                return new FixedLength(p.getNumeric().getNumericValue(), "px");
+                return FixedLength.getInstance(p.getNumeric().getNumericValue(), "px");
             }
             Length val = p.getLength();
             if (val != null) {
Index: src/java/org/apache/fop/fo/properties/FontSizePropertyMaker.java
===================================================================
--- src/java/org/apache/fop/fo/properties/FontSizePropertyMaker.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/FontSizePropertyMaker.java	(working copy)
@@ -55,9 +55,9 @@
             Property pp = propertyList.getFromParent(this.getPropId());
             int baseFontSize = computeClosestAbsoluteFontSize(pp.getLength().getValue());
             if (p.getEnum() == EN_LARGER) {
-                return new FixedLength((int)Math.round((baseFontSize * FONT_SIZE_GROWTH_FACTOR)));
+                return FixedLength.getInstance((int)Math.round((baseFontSize * FONT_SIZE_GROWTH_FACTOR)));
             } else {
-                return new FixedLength((int)Math.round((baseFontSize / FONT_SIZE_GROWTH_FACTOR)));
+                return FixedLength.getInstance((int)Math.round((baseFontSize / FONT_SIZE_GROWTH_FACTOR)));
             }
         }
         return super.convertProperty(p, propertyList, fo);
Index: src/java/org/apache/fop/fo/properties/KeepProperty.java
===================================================================
--- src/java/org/apache/fop/fo/properties/KeepProperty.java	(revision 532293)
+++ src/java/org/apache/fop/fo/properties/KeepProperty.java	(working copy)
@@ -165,4 +165,19 @@
         return this;
     }
 
+    public int hashCode() {
+        return withinLine.hashCode() << 3 +
+            withinColumn.hashCode() << 7 +
+            withinPage.hashCode() << 9;
+    }
+
+    public boolean equals(Object obj) {
+        if (! (obj instanceof KeepProperty))
+            return false;
+        KeepProperty c = (KeepProperty)obj;
+        return Property.eq(this.withinLine, c.withinLine) &&
+          Property.eq(this.withinColumn, c.withinColumn) &&
+          Property.eq(this.withinPage, c.withinPage);
+    }
+
 }
Index: src/java/org/apache/fop/fo/PropertyList.java
===================================================================
--- src/java/org/apache/fop/fo/PropertyList.java	(revision 532293)
+++ src/java/org/apache/fop/fo/PropertyList.java	(working copy)
@@ -38,6 +38,7 @@
 import org.apache.fop.fo.properties.CommonRelativePosition;
 import org.apache.fop.fo.properties.CommonTextDecoration;
 import org.apache.fop.fo.properties.Property;
+import org.apache.fop.fo.properties.PropertyCache;
 import org.apache.fop.fo.properties.PropertyMaker;
 import org.apache.fop.util.QName;
 
@@ -46,6 +47,8 @@
  */
 public abstract class PropertyList {
 
+    private static final PropertyCache cache = new PropertyCache();
+
     // writing-mode index
     private int writingMode;
 
@@ -53,7 +56,7 @@
 
     /** reference to the parent FO's propertyList **/
     protected PropertyList parentPropertyList = null;
-    private FObj fobj = null;
+    private final FObj fobj;
 
     private static Log log = LogFactory.getLog(PropertyList.class);
 
@@ -171,8 +174,9 @@
 
         PropertyMaker propertyMaker = findMaker(propId & Constants.PROPERTY_MASK);
         if (propertyMaker != null) {
-            return propertyMaker.get(propId & Constants.COMPOUND_MASK, this,
-                                         bTryInherit, bTryDefault);
+            Property p = propertyMaker.get(propId & Constants.COMPOUND_MASK, this,
+                                           bTryInherit, bTryDefault);
+            return (Property)cache.fetch(p);
         }
         return null;
     }
@@ -520,7 +524,7 @@
             return null;
         }
     }
-
+    
     /**
      * @param propID ID of property
      * @return new Property object
@@ -529,7 +533,7 @@
     private Property makeProperty(int propId) throws PropertyException {
         PropertyMaker propertyMaker = findMaker(propId);
         if (propertyMaker != null) {
-            return propertyMaker.make(this);
+            return (Property)cache.fetch(propertyMaker.make(this));
         } else {
             //log.error("property " + propertyName
             //                       + " ignored");
@@ -574,7 +578,7 @@
      */
     public CommonBorderPaddingBackground getBorderPaddingBackgroundProps() 
                 throws PropertyException {
-        return new CommonBorderPaddingBackground(this, getFObj());
+        return CommonBorderPaddingBackground.getInstance(this);
     }
     
     /**
@@ -583,7 +587,7 @@
      * @throws PropertyException if there's a problem while processing the properties
      */
     public CommonHyphenation getHyphenationProps() throws PropertyException {
-        return new CommonHyphenation(this);
+        return CommonHyphenation.getInstance(this);
     }
     
     /**
@@ -592,7 +596,7 @@
      * @throws PropertyException if there's a problem while processing the properties
      */
     public CommonMarginBlock getMarginBlockProps() throws PropertyException {
-        return new CommonMarginBlock(this);
+        return CommonMarginBlock.getInstance(this);
     }
     
     /**
@@ -601,7 +605,7 @@
      * @throws PropertyException if there's a problem while processing the properties
      */
     public CommonMarginInline getMarginInlineProps() throws PropertyException {
-        return new CommonMarginInline(this);
+      return new CommonMarginInline(this); // TODO: Replace with getInstance()
     }
     
     /**
@@ -610,7 +614,7 @@
      * @throws PropertyException if there's a problem while processing the properties
      */
     public CommonAccessibility getAccessibilityProps() throws PropertyException {
-        return new CommonAccessibility(this);
+        return CommonAccessibility.getInstance(this);
     }
 
     /**
@@ -619,8 +623,7 @@
      * @throws PropertyException if there's a problem while processing the properties
      */
     public CommonAural getAuralProps() throws PropertyException {
-        CommonAural props = new CommonAural(this);
-        return props;
+        return CommonAural.getInstance(this);
     }
 
     /**
@@ -629,7 +632,7 @@
      * @throws PropertyException if there's a problem while processing the properties
      */
     public CommonRelativePosition getRelativePositionProps() throws PropertyException {
-        return new CommonRelativePosition(this);
+        return CommonRelativePosition.getInstance(this);
     }
     
     /**
@@ -638,7 +641,7 @@
      * @throws PropertyException if there's a problem while processing the properties
      */
     public CommonAbsolutePosition getAbsolutePositionProps() throws PropertyException {
-        return new CommonAbsolutePosition(this);
+        return CommonAbsolutePosition.getInstance(this);
     }    
     
 
@@ -648,7 +651,7 @@
      * @throws PropertyException if there's a problem while processing the properties
      */
     public CommonFont getFontProps() throws PropertyException {
-        return new CommonFont(this);
+        return CommonFont.getInstance(this);
     }
     
     /**
Index: src/java/org/apache/fop/fo/flow/Block.java
===================================================================
--- src/java/org/apache/fop/fo/flow/Block.java	(revision 532293)
+++ src/java/org/apache/fop/fo/flow/Block.java	(working copy)
@@ -52,8 +52,6 @@
     private boolean initialPropertySetFound = false;
 
     // The value of properties relevant for fo:block.
-    private CommonAccessibility commonAccessibility;
-    private CommonAural commonAural;
     private CommonBorderPaddingBackground commonBorderPaddingBackground;
     private CommonFont commonFont;
     private CommonHyphenation commonHyphenation;
@@ -83,7 +81,10 @@
     private int whiteSpaceCollapse;
     private Numeric widows;
     private int wrapOption;
+
     // Unused but valid items, commented out for performance:
+    //     private CommonAccessibility commonAccessibility;
+    //     private CommonAural commonAural;
     //     private Length textDepth;
     //     private Length textAltitude;
     //     private int visibility;
@@ -101,8 +102,6 @@
      * @see org.apache.fop.fo.FObj#bind(PropertyList)
      */
     public void bind(PropertyList pList) throws FOPException {
-        commonAccessibility = pList.getAccessibilityProps();
-        commonAural = pList.getAuralProps();
         commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps();
         commonFont = pList.getFontProps();
         commonHyphenation = pList.getHyphenationProps();
@@ -348,20 +347,6 @@
     }
     
     /**
-     * @return Returns the commonAccessibility.
-     */
-    public CommonAccessibility getCommonAccessibility() {
-        return this.commonAccessibility;
-    }
-
-    /**
-     * @return Returns the commonAural.
-     */
-    public CommonAural getCommonAural() {
-        return this.commonAural;
-    }
-
-    /**
      * @return Returns the commonRelativePosition.
      */
     public CommonRelativePosition getCommonRelativePosition() {
Index: src/java/org/apache/fop/fo/StaticPropertyList.java
===================================================================
--- src/java/org/apache/fop/fo/StaticPropertyList.java	(revision 532293)
+++ src/java/org/apache/fop/fo/StaticPropertyList.java	(working copy)
@@ -24,8 +24,8 @@
  * the explicit set properties and another array to store cached values.
  */
 public class StaticPropertyList extends PropertyList {
-    private Property[] explicit;
-    private Property[] values;
+    private final Property[] explicit;
+    private final Property[] values;
     
     /**
      * Construct a StaticPropertyList. 
Index: src/java/org/apache/fop/fo/FOTreeBuilder.java
===================================================================
--- src/java/org/apache/fop/fo/FOTreeBuilder.java	(revision 532293)
+++ src/java/org/apache/fop/fo/FOTreeBuilder.java	(working copy)
@@ -110,11 +110,10 @@
      * true no Locator is passed to the FO tree nodes which would copy the information into
      * a SAX LocatorImpl instance.
      * @return true if no context information should be stored on each node in the FO tree.
+     * @deprecated Use FOUserAgent.isLocatorEnabled() instead.
      */
     protected boolean isLocatorDisabled() {
-        //TODO make this configurable through the FOUserAgent so people can optimize memory
-        //consumption.
-        return false;
+        return !userAgent.isLocatorEnabled();
     }
     
     /**
@@ -127,7 +126,7 @@
     
     /** @return a Locator instance if it is available and not disabled */
     protected Locator getEffectiveLocator() {
-        return (isLocatorDisabled() ? null : this.locator);
+        return (userAgent.isLocatorEnabled() ? this.locator : null);
     }
     
     /**
Index: src/java/org/apache/fop/fo/expr/PropertyParser.java
===================================================================
--- src/java/org/apache/fop/fo/expr/PropertyParser.java	(revision 532293)
+++ src/java/org/apache/fop/fo/expr/PropertyParser.java	(working copy)
@@ -293,7 +293,7 @@
                 prop = (Property) NumericOp.multiply(new NumberProperty(numPart.doubleValue()),
                                     propInfo.currentFontSize());
             } else {
-                prop = new FixedLength(numPart.doubleValue(), unitPart);
+                prop = FixedLength.getInstance(numPart.doubleValue(), unitPart);
             }
             break;
 
Index: build.xml
===================================================================
--- build.xml	(revision 532293)
+++ build.xml	(working copy)
@@ -152,7 +152,7 @@
 
   <property name="javac.debug" value="on"/>
   <property name="javac.optimize" value="off"/>
-  <property name="javac.deprecation" value="on"/>
+  <property name="javac.deprecation" value="off"/>
   <property name="javac.source" value="1.3"/>
   <property name="javac.target" value="1.3"/>
   <property name="javac.fork" value="no"/>
