From: Peter Bernard West Date: Wed, 18 Dec 2002 15:53:21 +0000 (+0000) Subject: Direct HTML content for web pages. X-Git-Tag: Alt-Design-integration-base~239 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=bd0b6ea20360b308b657f8dc06e896f1209f7dc8;p=xmlgraphics-fop.git Direct HTML content for web pages. Generated by emacs htmlize.el. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@195776 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/design/alt.design/FOAttributes.html b/src/documentation/content/design/alt.design/FOAttributes.html new file mode 100644 index 000000000..d7bf9184d --- /dev/null +++ b/src/documentation/content/design/alt.design/FOAttributes.html @@ -0,0 +1,405 @@ + + + + + FOAttributes.java + + + +
+package org.apache.fop.fo;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.fo.PropertyConsts;
+import org.apache.fop.fo.FObjectNames;
+import org.apache.fop.datatypes.Ints;
+import org.apache.fop.messaging.MessageHandler;
+import org.apache.fop.xml.FoXMLEvent;
+import org.apache.fop.xml.XMLNamespaces;
+
+import org.xml.sax.Attributes;
+
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Collections;
+import java.util.Arrays;
+
+/*
+ * FOAttributes.java
+ * $Id$
+ *
+ * Created: Wed Nov 14 15:19:51 2001
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ *
+ * @author <a href="mailto:pbwest@powerup.com.au">Peter B. West</a>
+ * @version $Revision$ $Name$
+ */
+/**
+ * The FO Attributes data structures and methods needed to manage the
+ * Attributes associated with FO nodes.
+ */
+
+public class FOAttributes {
+
+    private static final String tag = "$Name$";
+    private static final String revision = "$Revision$";
+
+    /**
+     * <i>nSpaceAttrMaps</i> is an <tt>ArrayList</tt> to hold the array of 
+     * <tt>HashMap</tt>s which contain the attribute lists for each
+     * namespace which may be active for a particular FO element.  The
+     * <tt>ArrayList</tt> is indexed by the URIIndex for this namespace
+     * which is maintained in an <tt>XMLNamespaces</tt> object by the
+     * <tt>FOTree</tt> object which is processing the FO input.  The
+     * values in the <tt>HashMap</tt>s are indexed by the local name of the
+     * attribute.
+     * The <tt>ArrayList</tt> will not be created for a particular instance
+     * of <tt>FOAttributes</tt> unless a namespace other than the standard
+     * XSL namespace is activated for this instance.
+     * See <i>foAttrMap</i>.
+     */
+    private ArrayList nSpaceAttrMaps;
+
+    /**
+     * <i>foAttrMap</i> is a <tt>HashMap</tt> to hold the FO namespace
+     * attribute list specified in the FO element with which this list is
+     * associated.  The <tt>String</tt> attribute value is stored
+     * indexed by the integer constant property identifier from
+     * <tt>PropertyConsts</tt>.
+     */
+    private HashMap foAttrMap = new HashMap(0);
+
+    /**
+     * A sorted array of the keys (property indices) of the values in
+     * <i>foAttrMap</i>.
+     */
+    private Integer[] foAttrKeys = null;
+
+    /**
+     * A static array of <tt>Integer</tt> as a template for the generation
+     * of the <i>foAttrKeys</i> array.
+     */
+    private static Integer[] integerArray
+                                    = new Integer[] { Ints.consts.get(0) };
+
+    /**
+     * Construct an <i>FOAttributes</i> object.
+     * <p>The <tt>Attributes</tt> object on the event is scanned, and each
+     * attribute is examined.  If the attribute is in the default namespace
+     * for fo: attributes, it is an fo: property, and its value is entered
+     * into the <i>foAttrMap</i> <tt>Hashmap</tt> indexed by the property
+     * index.
+     * <p>If the attribute does not belong to the default namespace, its
+     * value is entered into the appropriate <tt>HashMap</tt> in the
+     * <tt>ArrayList</tt> <i>nSpaceAttrMaps</i>, indexed by the attribute's
+     * local name.
+     * @param event - the FO XML event which triggered construction of the
+     * parent <tt>FONode</tt>.
+     * @param foNode - the <tt>FONode</tt> with which these attributes are
+     * associated.
+     */
+    public FOAttributes(FoXMLEvent event, FONode foNode) throws FOPException {
+
+        // If the event is null, there is no event associated with this
+        // node, probably because this is a manufactured node; e.g.,
+        // an "invented" FopageSequenceMaster.  The default initialisation
+        // includes an empty foAttrMap HashMap.
+        if (event == null) return;
+
+        if (event.getFoType() == FObjectNames.PCDATA)
+            return;  // go with the empty foAttrMap
+
+        // Create the foAttrMap.
+        Attributes attributes = event.getAttributes();
+        if (attributes == null) throw new FOPException
+                                       ("No Attributes in XMLEvent");
+        int propIndex;
+        HashMap tmpHash;
+        for (int i = 0; i < attributes.getLength(); i++) {
+            String attrUri = attributes.getURI(i);
+            String attrLocalname = attributes.getLocalName(i);
+            String attrQName = attributes.getQName(i);
+            int sep = attrQName.indexOf(':');
+            String prefix = attrQName.substring(0, (sep == -1 ? 0 : sep));
+            if (prefix.equals("xmlns")) break;
+            String attrValue = attributes.getValue(i);
+            int attrUriIndex = foNode.namespaces.getURIIndex(attrUri);
+
+            //System.out.println("FONode:" + event);
+            if (attrUriIndex == XMLNamespaces.DefAttrNSIndex) {
+                // Standard FO namespace
+                // Catch default namespace declaration here.
+                if (attrLocalname.equals("xmlns")) break;
+                // Is this a known (valid) property?
+                propIndex = PropNames.getPropertyIndex(attrLocalname);
+                    // Known attribute name
+                foAttrMap.put(Ints.consts.get(propIndex), attrValue);
+            } else { // Not the XSL FO namespace
+                int j;
+                if (nSpaceAttrMaps == null) {
+                    //Create the list
+                    System.out.println("Creating nSpaceAttrMaps");
+                    nSpaceAttrMaps = new ArrayList(attrUriIndex + 1);
+                    // Add the fo list
+                    for (j = 0; j < XMLNamespaces.DefAttrNSIndex; j++)
+                        nSpaceAttrMaps.add(new HashMap(0));
+
+                    System.out.println("Adding foAttrMap");
+                    nSpaceAttrMaps.add(foAttrMap);
+                }
+                // Make sure there are elements between the last current
+                // and the one to be added
+                for (j = nSpaceAttrMaps.size(); j <= attrUriIndex; j++)
+                    nSpaceAttrMaps.add(new HashMap(0));
+                
+                // Does a HashMap exist for this namespace?
+                if ((tmpHash =
+                     (HashMap)nSpaceAttrMaps.get(attrUriIndex)) == null) {
+                    tmpHash = new HashMap(1);
+                    nSpaceAttrMaps.set(attrUriIndex, tmpHash);
+                }
+                // Now put this value in the HashMap
+                tmpHash.put(attrLocalname, attrValue);
+            }
+        }
+        // Set up the sorted array of the foAttr keys, if foAttrMap has
+        // any entries.
+        if (foAttrMap.size() > 0) {
+            foAttrKeys = (Integer[])(foAttrMap.keySet().toArray(integerArray));
+            Arrays.sort(foAttrKeys);
+        }
+        // Finished with the Attributes object
+        event.setAttributes(null);
+    }
+
+    /**
+     * Get the default namespace attribute values as an unmodifiable
+     * <tt>Map</tt>.
+     * @return a unmodifiable <tt>Map</tt> containing the the attribute
+     * values for all of the default attribute namespace attributes in this
+     * attribute list, indexed by the property name index from
+     * <tt>PropNames</tt>.
+     */
+    public Map getFixedFoAttrMap() {
+        return Collections.unmodifiableMap((Map)foAttrMap);
+    }
+
+    /**
+     * Get the <tt>HashMap</tt> of all default namespace attributes.
+     * @return <tt>HashMap</tt> <i>foAttrMap</i> containing the the attribute
+     * values for all of the default attribute namespace attributes in this
+     * attribute list, indexed by the property name index from
+     * <tt>PropNames</tt>.  This HashMap may be changed by the calling
+     * process.
+     */
+    public HashMap getFoAttrMap() {
+        return foAttrMap;
+    }
+
+    /**
+     * Get the sorted array of property index keys for the default namespace
+     * attributes.
+     * @return <tt>Integer[]</tt> <i>foAttrKeys</i> containing the the
+     * sorted keys (the property indices from <tt>PropNames</tt>) of the
+     * attribute values for all of the default attribute namespace attributes
+     * in this attribute list.
+     * Warning: This array may be changed by the calling process.
+     */
+    public Integer[] getFoAttrKeys() {
+        return foAttrKeys;
+    }
+
+    /**
+     * A convenience method for accessing attribute values from the default
+     * attribute namespace.
+     * @param property an <tt>int</tt> containing the property name index
+     * from <tt>PropNames</tt>.
+     * @return a <tt>String</tt> containing the associated property value.
+     */
+    public String getFoAttrValue(int property) {
+        return (String)(foAttrMap.get(Ints.consts.get(property)));
+    }
+
+    /**
+     * A convenience method for accessing attribute values from the default
+     * attribute namespace.
+     * @param propertyName a <tt>String</tt> containing the property name.
+     * @return a <tt>String</tt> containing the associated property value.
+     */
+    public String getFoAttrValue(String propertyName)
+        throws PropertyException
+    {
+        return getFoAttrValue(PropNames.getPropertyIndex(propertyName));
+    }
+
+    /**
+     * Get an unmodifiable <tt>Map</tt> of the attribute values for a
+     * particular namespace.
+     * @param uriIndex an <tt>int</tt> containing the index of the attribute
+     * values namespace, maintained in an <tt>XMLEvent</tt> <tt>static</tt>
+     * array.
+     * @return an unmodifiable <tt>Map</tt> of the attribute values
+     * within the indexed namespace, for this attribute list, indexed by the
+     * local name of the attribute.  The <tt>Map</tt> returned is
+     * derived from the one maintained in <i>nSpaceAttrMaps</i>.
+     */
+    public Map getAttrMap(int uriIndex) {
+        if (uriIndex == XMLNamespaces.DefAttrNSIndex)
+            return Collections.unmodifiableMap((Map)foAttrMap);
+        if (nSpaceAttrMaps != null) {
+            if (uriIndex >= nSpaceAttrMaps.size()) return null;
+            return Collections.unmodifiableMap
+                    ((Map)(nSpaceAttrMaps.get(uriIndex)));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the value of an attribute in a particular namespace.
+     * @param uriIndex an <tt>int</tt> index of the URIs maintained
+     * by <tt>XMLEvent</tt>.
+     * @param localName a <tt>String</tt> with the local name of the
+     * attribute.  In the case of the default attribute namespace, this
+     * will be the fo property name.
+     * @return a <tt>String</tt> containing the value of the attribute.
+     */
+    public String getUriAttrValue(int uriIndex, String localName)
+        throws PropertyException
+    {
+        if (uriIndex == XMLNamespaces.DefAttrNSIndex)
+            return getFoAttrValue(PropNames.getPropertyIndex(localName));
+        return (String)
+                (((HashMap)nSpaceAttrMaps.get(uriIndex)).get(localName));
+    }
+
+    /**
+     * Get the size of the <i>foAttrMap</i> <tt>HashMap</tt>
+     * containing attributes for the default fo: namespace
+     * @return an <tt>int</tt> containing the size.
+     */
+    public int getFoAttrMapSize() {
+        return foAttrMap.size();
+    }
+
+    /**
+     * Get the size of the <i>nSpaceAttrMaps</i> <tt>ArrayList</tt>
+     * containing attribute namespaces active in this set of attributes.
+     * <i>N.B.</i> this may be zero if only the default attribute
+     * namespace has been seen in the attribute set.
+     * @return an <tt>int</tt> containing the size.
+     */
+    public int getNSpaceAttrMapsSize() {
+        if (nSpaceAttrMaps == null)
+            return 0;
+        return nSpaceAttrMaps.size();
+    }
+
+    /**
+     * Merge attributes from another <tt>FOAttributes</tt> into <i>this</i>.
+     * @param foAttrs the <tt>FOAttributes</tt> containing the attributes
+     * to merge.
+     */
+    public void merge(FOAttributes foAttrs) {
+        foAttrMap.putAll(foAttrs.getFoAttrMap());
+        int attrLen = foAttrs.getNSpaceAttrMapsSize();
+        if (attrLen != 0) {
+            // something to copy
+            if (nSpaceAttrMaps == null) {
+                // no "foreign" attribute lists in this
+                // copy the others in
+                nSpaceAttrMaps = new ArrayList(attrLen);
+            }
+            // If the merging ArrayList of namespaces is larger, add the
+            // extra elements and initialise each to an empty HashMap
+            for (int i = nSpaceAttrMaps.size(); i < attrLen; i++)
+                nSpaceAttrMaps.add(new HashMap(0));
+            // Except for foAttrs, which has already been merged, merge
+            // the entries from the merging foAttrs
+            for (int i = 0; i < attrLen; i++) {
+                // skip foAttrMap
+                if (i == XMLNamespaces.DefAttrNSIndex) continue;
+               ((HashMap) nSpaceAttrMaps.get(i))
+                       .putAll(foAttrs.getAttrMap(i));
+            }
+        }
+    }
+
+}// FOAttributes
+
+ + diff --git a/src/documentation/content/design/alt.design/FOPropertySets.html b/src/documentation/content/design/alt.design/FOPropertySets.html new file mode 100644 index 000000000..4912bd79a --- /dev/null +++ b/src/documentation/content/design/alt.design/FOPropertySets.html @@ -0,0 +1,362 @@ + + + + + FOPropertySets.java + + + +
+/*
+ * $Id$
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ *
+ * @author <a href="mailto:pbwest@powerup.com.au">Peter B. West</a>
+ * @version $Id$
+ */
+
+package org.apache.fop.fo;
+
+import java.lang.Character;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.StringTokenizer;
+
+// Only for tree property set partitions
+import java.util.BitSet;
+import java.util.Iterator;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.FObjectNames;
+import org.apache.fop.fo.PropertySets;
+import org.apache.fop.fo.PropNames;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.datatypes.Ints;
+import org.apache.fop.datastructs.ROIntArray;
+import org.apache.fop.datastructs.ROBitSet;
+
+/**
+ * Data class relating sets of properties to Flow Objects.
+ */
+
+public class FOPropertySets {
+
+    private static final String tag = "$Name$";
+    private static final String revision = "$Revision$";
+
+    public static final String packageNamePrefix = "org.apache.fop";
+
+    public static String getAttrSetName(int ancestry) throws FOPException {
+        if ((ancestry & FONode.MC_MARKER) != 0)
+            return "MARKER";
+        if ((ancestry & FONode.FLOW) != 0)
+            return "FLOW";
+        if ((ancestry & FONode.STATIC) != 0)
+            return "STATIC";
+        if ((ancestry & FONode.TITLE) != 0)
+            return "TITLE";
+        if ((ancestry & FONode.PAGESEQ) != 0)
+            return "PAGESEQ";
+        if ((ancestry & FONode.SEQ_MASTER) != 0)
+            return "SEQ_MASTER";
+        if ((ancestry & FONode.LAYOUT) != 0)
+            return "LAYOUT_MASTER";
+        if ((ancestry & FONode.DECLARATIONS) != 0)
+            return "DECLARATIONS";
+        if ((ancestry & FONode.ROOT) != 0)
+            return "ROOT";
+        throw new FOPException("Invalid attribute set: " + ancestry);
+    }
+
+    public static ROBitSet getAttrROBitSet(int ancestry)
+            throws FOPException
+    {
+        if ((ancestry & FONode.MC_MARKER) != 0)
+            return markerAllSet;
+        if ((ancestry & FONode.FLOW) != 0)
+            return flowAllSet;
+        if ((ancestry & FONode.STATIC) != 0)
+            return staticAllSet;
+        if ((ancestry & FONode.TITLE) != 0)
+            return titleAllSet;
+        if ((ancestry & FONode.PAGESEQ) != 0)
+            return pageSeqSet;
+        if ((ancestry & FONode.SEQ_MASTER) != 0)
+            return seqMasterSet;
+        if ((ancestry & FONode.LAYOUT) != 0)
+            return layoutMasterSet;
+        if ((ancestry & FONode.DECLARATIONS) != 0)
+            return declarationsAll;
+        if ((ancestry & FONode.ROOT) != 0)
+            return allProps;
+        throw new FOPException("Invalid attribute set: " + ancestry);
+    }
+
+    /**
+     * Set of all properties available at fo:root.
+     */
+    public static final ROBitSet allProps;
+
+    /**
+     * set of all properties which are
+     * usable within the declarations subtree.
+     */
+    public static final ROBitSet declarationsAll;
+
+    /**
+     * set of all properties which are
+     * usable within the page-sequence-master-set subtree.
+     */
+    public static final ROBitSet seqMasterSet;
+
+    /**
+     * set of all properties which are
+     * usable within the layout-master-set subtree.
+     */
+    public static final ROBitSet layoutMasterSet;
+
+    /**
+     * set of all properties which are
+     * usable within the page sequence subtree.
+     */
+    public static final ROBitSet pageSeqSet;
+
+    /**
+     * set of all properties which are
+     * usable within the fo:flow subtree.
+     */
+    public static final ROBitSet flowAllSet;
+
+    /**
+     * set of all properties which are
+     * usable <i>within</i> the fo:marker subtree.
+     */
+    public static final ROBitSet markerAllSet;
+
+    /**
+     * set of all properties which are
+     * usable within the fo:static-content subtree.
+     */
+    public static final ROBitSet staticAllSet;
+
+    /**
+     * set of all properties which are
+     * usable within the fo:title subtree.
+     */
+    public static final ROBitSet titleAllSet;
+
+    static {
+
+        // fill the BitSet of all properties
+        BitSet allprops = new BitSet(PropNames.LAST_PROPERTY_INDEX + 1);
+        allprops.set(1, PropNames.LAST_PROPERTY_INDEX);
+
+        allProps = new ROBitSet(allprops);
+
+        //root only set of properties - properties for exclusive use on the
+        // root element
+        BitSet rootonly = new BitSet(PropNames.MEDIA_USAGE + 1);
+        rootonly.set(PropNames.MEDIA_USAGE);
+
+        //declarations only set of properties - properties for exclusive use
+        // in the declarations SUBTREE
+        BitSet declarationsonly = new BitSet();
+        declarationsonly.set(PropNames.COLOR_PROFILE_NAME);
+        declarationsonly.set(PropNames.RENDERING_INTENT);
+
+        // set of all declarations properties - properties which may be
+        // used in the declarations SUBTREE
+        BitSet declarationsall = (BitSet)declarationsonly.clone();
+        declarationsall.set(PropNames.SRC);
+
+        declarationsAll = new ROBitSet(declarationsall);
+
+        // seq-master-only set of properties for exclusive use within
+        // the page-sequence-master subtree
+        BitSet seqmasteronly = new BitSet();
+        seqmasteronly.set(PropNames.MAXIMUM_REPEATS);
+        seqmasteronly.set(PropNames.PAGE_POSITION);
+        seqmasteronly.set(PropNames.ODD_OR_EVEN);
+        seqmasteronly.set(PropNames.BLANK_OR_NOT_BLANK);
+
+        // seq-master-set set of properties for use within
+        // the page-sequence-master subtree
+        BitSet seqmasterset = (BitSet)seqmasteronly.clone();
+        seqmasterset.set(PropNames.MASTER_NAME);
+        seqmasterset.set(PropNames.MASTER_REFERENCE);
+
+        seqMasterSet = new ROBitSet(seqmasterset);
+
+        //layout-master-set only set of properties - properties for exclusive
+        // use within the layout-master-set SUBTREE
+        BitSet layoutmasteronly = (BitSet)seqmasteronly.clone();
+        layoutmasteronly.set(PropNames.MASTER_NAME);
+        layoutmasteronly.set(PropNames.PAGE_HEIGHT);
+        layoutmasteronly.set(PropNames.PAGE_WIDTH);
+        layoutmasteronly.set(PropNames.COLUMN_COUNT);
+        layoutmasteronly.set(PropNames.COLUMN_GAP);
+        layoutmasteronly.set(PropNames.REGION_NAME);
+        layoutmasteronly.set(PropNames.EXTENT);
+        layoutmasteronly.set(PropNames.PRECEDENCE);
+
+        // set of all layout-master-set properties - properties which may be
+        // used in the layout-master-set SUBTREE
+        // Add the layout-master-set exclusive properties
+        BitSet layoutmasterset = (BitSet)layoutmasteronly.clone();
+
+        layoutmasterset.set(PropNames.MASTER_REFERENCE);
+        layoutmasterset.set(PropNames.REFERENCE_ORIENTATION);
+        layoutmasterset.set(PropNames.WRITING_MODE);
+        layoutmasterset.set(PropNames.CLIP);
+        layoutmasterset.set(PropNames.DISPLAY_ALIGN);
+        layoutmasterset.set(PropNames.OVERFLOW);
+
+        // Add the common margin properties - block
+	layoutmasterset.or(PropertySets.marginBlockSet);
+        // Add the common border properties
+	layoutmasterset.or(PropertySets.borderSet);
+        // Add the common padding properties
+	layoutmasterset.or(PropertySets.paddingSet);
+        // Add the common background properties
+	layoutmasterset.or(PropertySets.backgroundSet);
+        layoutMasterSet = new ROBitSet(layoutmasterset);
+
+        BitSet flowonlyset = new BitSet();
+        flowonlyset.set(PropNames.MARKER_CLASS_NAME);
+
+        BitSet staticonlyset = new BitSet();
+        staticonlyset.set(PropNames.RETRIEVE_CLASS_NAME);
+        staticonlyset.set(PropNames.RETRIEVE_POSITION);
+        staticonlyset.set(PropNames.RETRIEVE_BOUNDARY);
+
+        // pageseqonly contains the properties which are exclusive to
+        // fo:pagesequence
+        BitSet pageseqonly = new BitSet();
+        pageseqonly.set(PropNames.FORMAT);
+        pageseqonly.set(PropNames.LETTER_VALUE);
+        pageseqonly.set(PropNames.GROUPING_SEPARATOR);
+        pageseqonly.set(PropNames.GROUPING_SIZE);
+        pageseqonly.set(PropNames.INITIAL_PAGE_NUMBER);
+        pageseqonly.set(PropNames.FORCE_PAGE_COUNT);
+
+        // pageseqset may contain any of the exclusive elements of the
+        // flow set or the static-content set, which may be accessed by
+        // the from-nearest-specified-property() function.
+        BitSet pageseqset = (BitSet)allprops.clone();
+        pageseqset.andNot(rootonly);
+        pageseqset.andNot(declarationsonly);
+        pageseqset.andNot(layoutmasteronly);
+        pageSeqSet = new ROBitSet(pageseqset);
+
+        BitSet flowallset = (BitSet)pageseqset.clone();
+        flowallset.andNot(pageseqonly);
+        flowallset.andNot(staticonlyset);
+
+        flowAllSet = new ROBitSet(flowallset);
+
+        BitSet staticallset = (BitSet)pageseqset.clone();
+        staticallset.andNot(pageseqonly);
+        staticallset.andNot(flowonlyset);
+
+        staticAllSet = new ROBitSet(staticallset);
+
+        BitSet markerallset = (BitSet)flowallset.clone();
+        markerallset.clear(PropNames.MARKER_CLASS_NAME);
+
+        markerAllSet = new ROBitSet(markerallset);
+
+        // markers are not allowed within fo:title
+        titleAllSet = markerAllSet;
+    }
+
+    /**
+     * ReferenceArea trait mappings.  Immutable BitSet of FOs for which
+     * the <tt>reference-area</tt> trait is true.
+     */
+    public static final ROBitSet isReferenceArea;
+    static {
+        BitSet refareas = new BitSet(FObjectNames.LAST_FO + 1);
+        refareas.set(FObjectNames.SIMPLE_PAGE_MASTER);
+        refareas.set(FObjectNames.REGION_AFTER);
+        refareas.set(FObjectNames.REGION_BEFORE);
+        refareas.set(FObjectNames.REGION_BODY);
+        refareas.set(FObjectNames.REGION_END);
+        refareas.set(FObjectNames.REGION_START);
+        refareas.set(FObjectNames.BLOCK_CONTAINER);
+        refareas.set(FObjectNames.INLINE_CONTAINER);
+        refareas.set(FObjectNames.TABLE);
+        refareas.set(FObjectNames.TABLE_CAPTION);
+        refareas.set(FObjectNames.TABLE_CELL);
+        refareas.set(FObjectNames.TITLE);
+
+        isReferenceArea = new ROBitSet(refareas);
+    }
+
+}
+
+
+ + diff --git a/src/documentation/content/design/alt.design/PropNames.html b/src/documentation/content/design/alt.design/PropNames.html new file mode 100644 index 000000000..7b3e084a7 --- /dev/null +++ b/src/documentation/content/design/alt.design/PropNames.html @@ -0,0 +1,867 @@ + + + + + PropNames.java + + + +
+/*
+ * $Id$
+ * Copyright (C) 2001-2002 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ * @author <a href="mailto:pbwest@powerup.com.au">Peter B. West</a>
+ * @version $Revision$ $Name$
+ */
+
+package org.apache.fop.fo;
+
+import java.util.HashMap;
+
+import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.datatypes.Ints;
+
+/**
+ * A class of constants; an array of all property names and the constants
+ * by which to refer to them.
+ */
+
+public class PropNames {
+
+    private static final String tag = "$Name$";
+    private static final String revision = "$Revision$";
+
+    /*
+     * List of property constants in property processing order -
+     * FONT, FONT_SIZE first
+     * Shorthands must precede any of their expansion elements.
+     * Compounds must precede any of their components.
+     * The list of property constants can be regenerated in XEmacs by setting
+     * the region on the list of constants. (C-Space at the beginning,
+     * move to last line, C-x C-x to exchange mark and point.)  Then run
+     * a shell command on the region with replacement (M-1 M-|).  Use
+     * the perl command:
+     * perl -p -e 'BEGIN{$n=0};$n++ if s/= [0-9]+,/= $n,/'
+     * Alternatively, start at a given point in the list by setting the
+     * appropriate start value for $n.
+     *
+     * in vi, set mark `a' at the last line and
+     * !'aperl... etc
+     */
+     /** Constant for matching property defined in <i>XSLFO</i>. */
+
+    public static final int
+                                    NO_PROPERTY = 0,
+            // Properties setting up environment for from-table-column(),
+            // e.g. font-size = from-table-column()
+                                  COLUMN_NUMBER = 1,
+                         NUMBER_COLUMNS_SPANNED = 2,
+            // Properties setting font-size first
+            // Shorthand first
+                                           FONT = 3,
+                                      FONT_SIZE = 4,
+            // Writing mode early for handling of corresponding values
+                                   WRITING_MODE = 5,
+            // All other shorthands
+                                     BACKGROUND = 6,
+                            BACKGROUND_POSITION = 7,
+                                         BORDER = 8,
+                                   BORDER_COLOR = 9,
+                                   BORDER_STYLE = 10,
+                                   BORDER_WIDTH = 11,
+                                  BORDER_BOTTOM = 12,
+                                    BORDER_LEFT = 13,
+                                   BORDER_RIGHT = 14,
+                                     BORDER_TOP = 15,
+                                 BORDER_SPACING = 16,
+                                            CUE = 17,
+                                         MARGIN = 18,
+                                        PADDING = 19,
+                               PAGE_BREAK_AFTER = 20,
+                              PAGE_BREAK_BEFORE = 21,
+                              PAGE_BREAK_INSIDE = 22,
+                                          PAUSE = 23,
+                                       POSITION = 24,
+                                           SIZE = 25,
+                                 VERTICAL_ALIGN = 26,
+                                    WHITE_SPACE = 27,
+                                       XML_LANG = 28,
+            // Non-shorthand properties
+            // Within these, compounds precede their components
+            // and corresponding relative properties
+            // precede corresponding absolute properties
+                              ABSOLUTE_POSITION = 29,
+                                   ACTIVE_STATE = 30,
+                               ALIGNMENT_ADJUST = 31,
+                             ALIGNMENT_BASELINE = 32,
+                                   AUTO_RESTORE = 33,
+                                        AZIMUTH = 34,
+                          BACKGROUND_ATTACHMENT = 35,
+                               BACKGROUND_COLOR = 36,
+                               BACKGROUND_IMAGE = 37,
+                 BACKGROUND_POSITION_HORIZONTAL = 38,
+                   BACKGROUND_POSITION_VERTICAL = 39,
+                              BACKGROUND_REPEAT = 40,
+                                 BASELINE_SHIFT = 41,
+                             BLANK_OR_NOT_BLANK = 42,
+                    BLOCK_PROGRESSION_DIMENSION = 43,
+            BLOCK_PROGRESSION_DIMENSION_MINIMUM = 44,
+            BLOCK_PROGRESSION_DIMENSION_OPTIMUM = 45,
+            BLOCK_PROGRESSION_DIMENSION_MAXIMUM = 46,
+
+        // Border corresponding properties
+                             BORDER_AFTER_COLOR = 47,
+                        BORDER_AFTER_PRECEDENCE = 48,
+                             BORDER_AFTER_STYLE = 49,
+                             BORDER_AFTER_WIDTH = 50,
+                      BORDER_AFTER_WIDTH_LENGTH = 51,
+              BORDER_AFTER_WIDTH_CONDITIONALITY = 52,
+                            BORDER_BEFORE_COLOR = 53,
+                       BORDER_BEFORE_PRECEDENCE = 54,
+                            BORDER_BEFORE_STYLE = 55,
+                            BORDER_BEFORE_WIDTH = 56,
+                     BORDER_BEFORE_WIDTH_LENGTH = 57,
+             BORDER_BEFORE_WIDTH_CONDITIONALITY = 58,
+                               BORDER_END_COLOR = 59,
+                          BORDER_END_PRECEDENCE = 60,
+                               BORDER_END_STYLE = 61,
+                               BORDER_END_WIDTH = 62,
+                        BORDER_END_WIDTH_LENGTH = 63,
+                BORDER_END_WIDTH_CONDITIONALITY = 64,
+                             BORDER_START_COLOR = 65,
+                        BORDER_START_PRECEDENCE = 66,
+                             BORDER_START_STYLE = 67,
+                             BORDER_START_WIDTH = 68,
+                      BORDER_START_WIDTH_LENGTH = 69,
+              BORDER_START_WIDTH_CONDITIONALITY = 70,
+
+                            BORDER_BOTTOM_COLOR = 71,
+                            BORDER_BOTTOM_STYLE = 72,
+                            BORDER_BOTTOM_WIDTH = 73,
+                              BORDER_LEFT_COLOR = 74,
+                              BORDER_LEFT_STYLE = 75,
+                              BORDER_LEFT_WIDTH = 76,
+                             BORDER_RIGHT_COLOR = 77,
+                             BORDER_RIGHT_STYLE = 78,
+                             BORDER_RIGHT_WIDTH = 79,
+                               BORDER_TOP_COLOR = 80,
+                               BORDER_TOP_STYLE = 81,
+                               BORDER_TOP_WIDTH = 82,
+
+                                BORDER_COLLAPSE = 83,
+                              BORDER_SEPARATION = 84,
+  BORDER_SEPARATION_BLOCK_PROGRESSION_DIRECTION = 85,
+ BORDER_SEPARATION_INLINE_PROGRESSION_DIRECTION = 86,
+                                         BOTTOM = 87,
+                                    BREAK_AFTER = 88,
+                                   BREAK_BEFORE = 89,
+                                   CAPTION_SIDE = 90,
+                                      CASE_NAME = 91,
+                                     CASE_TITLE = 92,
+                                      CHARACTER = 93,
+                                          CLEAR = 94,
+                                           CLIP = 95,
+                                          COLOR = 96,
+                             COLOR_PROFILE_NAME = 97,
+                                   COLUMN_COUNT = 98,
+                                     COLUMN_GAP = 99,
+                                   COLUMN_WIDTH = 100,
+                                 CONTENT_HEIGHT = 101,
+                                   CONTENT_TYPE = 102,
+                                  CONTENT_WIDTH = 103,
+                                        COUNTRY = 104,
+                                      CUE_AFTER = 105,
+                                     CUE_BEFORE = 106,
+                   DESTINATION_PLACEMENT_OFFSET = 107,
+                                      DIRECTION = 108,
+                                  DISPLAY_ALIGN = 109,
+                              DOMINANT_BASELINE = 110,
+                                      ELEVATION = 111,
+                                    EMPTY_CELLS = 112,
+                                     END_INDENT = 113,
+                                       ENDS_ROW = 114,
+                                         EXTENT = 115,
+                           EXTERNAL_DESTINATION = 116,
+                                          FLOAT = 117,
+                                      FLOW_NAME = 118,
+                                    FONT_FAMILY = 119,
+                        FONT_SELECTION_STRATEGY = 120,
+                               FONT_SIZE_ADJUST = 121,
+                                   FONT_STRETCH = 122,
+                                     FONT_STYLE = 123,
+                                   FONT_VARIANT = 124,
+                                    FONT_WEIGHT = 125,
+                               FORCE_PAGE_COUNT = 126,
+                                         FORMAT = 127,
+                   GLYPH_ORIENTATION_HORIZONTAL = 128,
+                     GLYPH_ORIENTATION_VERTICAL = 129,
+                             GROUPING_SEPARATOR = 130,
+                                  GROUPING_SIZE = 131,
+                                         HEIGHT = 132,
+                                      HYPHENATE = 133,
+                          HYPHENATION_CHARACTER = 134,
+                               HYPHENATION_KEEP = 135,
+                       HYPHENATION_LADDER_COUNT = 136,
+               HYPHENATION_PUSH_CHARACTER_COUNT = 137,
+             HYPHENATION_REMAIN_CHARACTER_COUNT = 138,
+                                             ID = 139,
+                           INDICATE_DESTINATION = 140,
+                            INITIAL_PAGE_NUMBER = 141,
+                   INLINE_PROGRESSION_DIMENSION = 142,
+           INLINE_PROGRESSION_DIMENSION_MINIMUM = 143,
+           INLINE_PROGRESSION_DIMENSION_OPTIMUM = 144,
+           INLINE_PROGRESSION_DIMENSION_MAXIMUM = 145,
+                           INTERNAL_DESTINATION = 146,
+                             INTRUSION_DISPLACE = 147,
+                                  KEEP_TOGETHER = 148,
+                      KEEP_TOGETHER_WITHIN_LINE = 149,
+                      KEEP_TOGETHER_WITHIN_PAGE = 150,
+                    KEEP_TOGETHER_WITHIN_COLUMN = 151,
+                                 KEEP_WITH_NEXT = 152,
+                     KEEP_WITH_NEXT_WITHIN_LINE = 153,
+                     KEEP_WITH_NEXT_WITHIN_PAGE = 154,
+                   KEEP_WITH_NEXT_WITHIN_COLUMN = 155,
+                             KEEP_WITH_PREVIOUS = 156,
+                 KEEP_WITH_PREVIOUS_WITHIN_LINE = 157,
+                 KEEP_WITH_PREVIOUS_WITHIN_PAGE = 158,
+               KEEP_WITH_PREVIOUS_WITHIN_COLUMN = 159,
+                                       LANGUAGE = 160,
+                           LAST_LINE_END_INDENT = 161,
+                               LEADER_ALIGNMENT = 162,
+                                  LEADER_LENGTH = 163,
+                          LEADER_LENGTH_MINIMUM = 164,
+                          LEADER_LENGTH_OPTIMUM = 165,
+                          LEADER_LENGTH_MAXIMUM = 166,
+                                 LEADER_PATTERN = 167,
+                           LEADER_PATTERN_WIDTH = 168,
+                                           LEFT = 169,
+                                 LETTER_SPACING = 170,
+                         LETTER_SPACING_MINIMUM = 171,
+                         LETTER_SPACING_OPTIMUM = 172,
+                         LETTER_SPACING_MAXIMUM = 173,
+                  LETTER_SPACING_CONDITIONALITY = 174,
+                      LETTER_SPACING_PRECEDENCE = 175,
+                                   LETTER_VALUE = 176,
+                             LINEFEED_TREATMENT = 177,
+                                    LINE_HEIGHT = 178,
+                            LINE_HEIGHT_MINIMUM = 179,
+                            LINE_HEIGHT_OPTIMUM = 180,
+                            LINE_HEIGHT_MAXIMUM = 181,
+                     LINE_HEIGHT_CONDITIONALITY = 182,
+                         LINE_HEIGHT_PRECEDENCE = 183,
+                   LINE_HEIGHT_SHIFT_ADJUSTMENT = 184,
+                         LINE_STACKING_STRATEGY = 185,
+
+                              MARKER_CLASS_NAME = 186,
+                                    MASTER_NAME = 187,
+                               MASTER_REFERENCE = 188,
+                                     MAX_HEIGHT = 189,
+                                MAXIMUM_REPEATS = 190,
+                                      MAX_WIDTH = 191,
+                                    MEDIA_USAGE = 192,
+                                     MIN_HEIGHT = 193,
+                                      MIN_WIDTH = 194,
+                        NUMBER_COLUMNS_REPEATED = 195,
+                            NUMBER_ROWS_SPANNED = 196,
+                                    ODD_OR_EVEN = 197,
+                                        ORPHANS = 198,
+                                       OVERFLOW = 199,
+
+        // Padding corresponding properties
+                                  PADDING_AFTER = 200,
+                           PADDING_AFTER_LENGTH = 201,
+                   PADDING_AFTER_CONDITIONALITY = 202,
+                                 PADDING_BEFORE = 203,
+                          PADDING_BEFORE_LENGTH = 204,
+                  PADDING_BEFORE_CONDITIONALITY = 205,
+                                    PADDING_END = 206,
+                             PADDING_END_LENGTH = 207,
+                     PADDING_END_CONDITIONALITY = 208,
+                                  PADDING_START = 209,
+                           PADDING_START_LENGTH = 210,
+                   PADDING_START_CONDITIONALITY = 211,
+
+                                 PADDING_BOTTOM = 212,
+                                   PADDING_LEFT = 213,
+                                  PADDING_RIGHT = 214,
+                                    PADDING_TOP = 215,
+
+                                    PAGE_HEIGHT = 216,
+                                  PAGE_POSITION = 217,
+                                     PAGE_WIDTH = 218,
+                                    PAUSE_AFTER = 219,
+                                   PAUSE_BEFORE = 220,
+                                          PITCH = 221,
+                                    PITCH_RANGE = 222,
+                                    PLAY_DURING = 223,
+                                     PRECEDENCE = 224,
+            PROVISIONAL_DISTANCE_BETWEEN_STARTS = 225,
+                   PROVISIONAL_LABEL_SEPARATION = 226,
+                          REFERENCE_ORIENTATION = 227,
+                                         REF_ID = 228,
+                                    REGION_NAME = 229,
+                                 RELATIVE_ALIGN = 230,
+                              RELATIVE_POSITION = 231,
+                               RENDERING_INTENT = 232,
+                              RETRIEVE_BOUNDARY = 233,
+                            RETRIEVE_CLASS_NAME = 234,
+                              RETRIEVE_POSITION = 235,
+                                       RICHNESS = 236,
+                                          RIGHT = 237,
+                                           ROLE = 238,
+                                     RULE_STYLE = 239,
+                                 RULE_THICKNESS = 240,
+                                        SCALING = 241,
+                                 SCALING_METHOD = 242,
+                                   SCORE_SPACES = 243,
+                                         SCRIPT = 244,
+                               SHOW_DESTINATION = 245,
+                                SOURCE_DOCUMENT = 246,
+
+        // Space/margin corresponding properties
+                                    SPACE_AFTER = 247,
+                            SPACE_AFTER_MINIMUM = 248,
+                            SPACE_AFTER_OPTIMUM = 249,
+                            SPACE_AFTER_MAXIMUM = 250,
+                     SPACE_AFTER_CONDITIONALITY = 251,
+                         SPACE_AFTER_PRECEDENCE = 252,
+                                   SPACE_BEFORE = 253,
+                           SPACE_BEFORE_MINIMUM = 254,
+                           SPACE_BEFORE_OPTIMUM = 255,
+                           SPACE_BEFORE_MAXIMUM = 256,
+                    SPACE_BEFORE_CONDITIONALITY = 257,
+                        SPACE_BEFORE_PRECEDENCE = 258,
+                                      SPACE_END = 259,
+                              SPACE_END_MINIMUM = 260,
+                              SPACE_END_OPTIMUM = 261,
+                              SPACE_END_MAXIMUM = 262,
+                       SPACE_END_CONDITIONALITY = 263,
+                           SPACE_END_PRECEDENCE = 264,
+                                    SPACE_START = 265,
+                            SPACE_START_MINIMUM = 266,
+                            SPACE_START_OPTIMUM = 267,
+                            SPACE_START_MAXIMUM = 268,
+                     SPACE_START_CONDITIONALITY = 269,
+                         SPACE_START_PRECEDENCE = 270,
+
+                                  MARGIN_BOTTOM = 271,
+                                    MARGIN_LEFT = 272,
+                                   MARGIN_RIGHT = 273,
+                                     MARGIN_TOP = 274,
+
+                                           SPAN = 275,
+                                          SPEAK = 276,
+                                   SPEAK_HEADER = 277,
+                                  SPEAK_NUMERAL = 278,
+                              SPEAK_PUNCTUATION = 279,
+                                    SPEECH_RATE = 280,
+                                            SRC = 281,
+                                   START_INDENT = 282,
+                                 STARTING_STATE = 283,
+                                     STARTS_ROW = 284,
+                                         STRESS = 285,
+                         SUPPRESS_AT_LINE_BREAK = 286,
+                                      SWITCH_TO = 287,
+                                   TABLE_LAYOUT = 288,
+                     TABLE_OMIT_FOOTER_AT_BREAK = 289,
+                     TABLE_OMIT_HEADER_AT_BREAK = 290,
+                    TARGET_PRESENTATION_CONTEXT = 291,
+                      TARGET_PROCESSING_CONTEXT = 292,
+                              TARGET_STYLESHEET = 293,
+                                     TEXT_ALIGN = 294,
+                                TEXT_ALIGN_LAST = 295,
+                                  TEXT_ALTITUDE = 296,
+                                TEXT_DECORATION = 297,
+                                     TEXT_DEPTH = 298,
+                                    TEXT_INDENT = 299,
+                                    TEXT_SHADOW = 300,
+                                 TEXT_TRANSFORM = 301,
+                                            TOP = 302,
+                            TREAT_AS_WORD_SPACE = 303,
+                                   UNICODE_BIDI = 304,
+        USAGE_CONTEXT_OF_SUPPRESS_AT_LINE_BREAK = 305,
+                                     VISIBILITY = 306,
+                                   VOICE_FAMILY = 307,
+                                         VOLUME = 308,
+                           WHITE_SPACE_COLLAPSE = 309,
+                          WHITE_SPACE_TREATMENT = 310,
+                                         WIDOWS = 311,
+                                          WIDTH = 312,
+                                   WORD_SPACING = 313,
+                           WORD_SPACING_MINIMUM = 314,
+                           WORD_SPACING_OPTIMUM = 315,
+                           WORD_SPACING_MAXIMUM = 316,
+                    WORD_SPACING_CONDITIONALITY = 317,
+                        WORD_SPACING_PRECEDENCE = 318,
+                                    WRAP_OPTION = 319,
+                                        Z_INDEX = 320,
+        
+                            LAST_PROPERTY_INDEX = Z_INDEX;
+
+
+    /**
+     * A String[] array containing the names of all of the FO properties.
+     * The array is effectively 1-based, as the first element is null.
+     * The list of int constants referring to the properties must be manually
+     * kept in sync with the names in this array, as the constants can be
+     * used to index into this, and the other property arrays.
+     */
+
+    private static final String[] propertyNames = {
+                                        "no-property"  // 0
+
+                                     ,"column-number"  // 1
+                            ,"number-columns-spanned"  // 2
+
+                                              ,"font"  // 3
+                                         ,"font-size"  // 4
+
+                                      ,"writing-mode"  // 5
+
+                                        ,"background"  // 6
+                               ,"background-position"  // 7
+                                            ,"border"  // 8
+                                      ,"border-color"  // 9
+                                      ,"border-style"  // 10
+                                      ,"border-width"  // 11
+                                     ,"border-bottom"  // 12
+                                       ,"border-left"  // 13
+                                      ,"border-right"  // 14
+                                        ,"border-top"  // 15
+                                    ,"border-spacing"  // 16
+                                               ,"cue"  // 17
+                                            ,"margin"  // 18
+                                           ,"padding"  // 19
+                                  ,"page-break-after"  // 20
+                                 ,"page-break-before"  // 21
+                                 ,"page-break-inside"  // 22
+                                             ,"pause"  // 23
+                                          ,"position"  // 24
+                                              ,"size"  // 25
+                                    ,"vertical-align"  // 26
+                                       ,"white-space"  // 27
+                                          ,"xml:lang"  // 28
+
+                                 ,"absolute-position"  // 29
+                                      ,"active-state"  // 30
+                                  ,"alignment-adjust"  // 31
+                                ,"alignment-baseline"  // 32
+                                      ,"auto-restore"  // 33
+                                           ,"azimuth"  // 34
+                             ,"background-attachment"  // 35
+                                  ,"background-color"  // 36
+                                  ,"background-image"  // 37
+                    ,"background-position-horizontal"  // 38
+                      ,"background-position-vertical"  // 39
+                                 ,"background-repeat"  // 40
+                                    ,"baseline-shift"  // 41
+                                ,"blank-or-not-blank"  // 42
+                       ,"block-progression-dimension"  // 43
+               ,"block-progression-dimension.minimum"  // 44
+               ,"block-progression-dimension.optimum"  // 45
+               ,"block-progression-dimension.maximum"  // 46
+
+                                ,"border-after-color"  // 47
+                           ,"border-after-precedence"  // 48
+                                ,"border-after-style"  // 49
+                                ,"border-after-width"  // 50
+                         ,"border-after-width.length"  // 51
+                 ,"border-after-width.conditionality"  // 52
+                               ,"border-before-color"  // 53
+                          ,"border-before-precedence"  // 54
+                               ,"border-before-style"  // 55
+                               ,"border-before-width"  // 56
+                        ,"border-before-width.length"  // 57
+                ,"border-before-width.conditionality"  // 58
+                                  ,"border-end-color"  // 59
+                             ,"border-end-precedence"  // 60
+                                  ,"border-end-style"  // 61
+                                  ,"border-end-width"  // 62
+                           ,"border-end-width.length"  // 63
+                   ,"border-end-width.conditionality"  // 64
+                                ,"border-start-color"  // 65
+                           ,"border-start-precedence"  // 66
+                                ,"border-start-style"  // 67
+                                ,"border-start-width"  // 68
+                         ,"border-start-width.length"  // 69
+                 ,"border-start-width.conditionality"  // 70
+
+                               ,"border-bottom-color"  // 71
+                               ,"border-bottom-style"  // 72
+                               ,"border-bottom-width"  // 73
+                                 ,"border-left-color"  // 74
+                                 ,"border-left-style"  // 75
+                                 ,"border-left-width"  // 76
+                                ,"border-right-color"  // 77
+                                ,"border-right-style"  // 78
+                                ,"border-right-width"  // 79
+                                  ,"border-top-color"  // 80
+                                  ,"border-top-style"  // 81
+                                  ,"border-top-width"  // 82
+
+                                   ,"border-collapse"  // 83
+                                 ,"border-separation"  // 84
+     ,"border-separation.block-progression-direction"  // 85
+    ,"border-separation.inline-progression-direction"  // 86
+                                            ,"bottom"  // 87
+                                       ,"break-after"  // 88
+                                      ,"break-before"  // 89
+                                      ,"caption-side"  // 90
+                                         ,"case-name"  // 91
+                                        ,"case-title"  // 92
+                                         ,"character"  // 93
+                                             ,"clear"  // 94
+                                              ,"clip"  // 95
+                                             ,"color"  // 96
+                                ,"color-profile-name"  // 97
+                                      ,"column-count"  // 98
+                                        ,"column-gap"  // 99
+                                      ,"column-width"  // 100
+                                    ,"content-height"  // 101
+                                      ,"content-type"  // 102
+                                     ,"content-width"  // 103
+                                           ,"country"  // 104
+                                         ,"cue-after"  // 105
+                                        ,"cue-before"  // 106
+                      ,"destination-placement-offset"  // 107
+                                         ,"direction"  // 108
+                                     ,"display-align"  // 109
+                                 ,"dominant-baseline"  // 110
+                                         ,"elevation"  // 111
+                                       ,"empty-cells"  // 112
+                                        ,"end-indent"  // 113
+                                          ,"ends-row"  // 114
+                                            ,"extent"  // 115
+                              ,"external-destination"  // 116
+                                             ,"float"  // 117
+                                         ,"flow-name"  // 118
+                                       ,"font-family"  // 119
+                           ,"font-selection-strategy"  // 120
+                                  ,"font-size-adjust"  // 121
+                                      ,"font-stretch"  // 122
+                                        ,"font-style"  // 123
+                                      ,"font-variant"  // 124
+                                       ,"font-weight"  // 125
+                                  ,"force-page-count"  // 126
+                                            ,"format"  // 127
+                      ,"glyph-orientation-horizontal"  // 128
+                        ,"glyph-orientation-vertical"  // 129
+                                ,"grouping-separator"  // 130
+                                     ,"grouping-size"  // 131
+                                            ,"height"  // 132
+                                         ,"hyphenate"  // 133
+                             ,"hyphenation-character"  // 134
+                                  ,"hyphenation-keep"  // 135
+                          ,"hyphenation-ladder-count"  // 136
+                  ,"hyphenation-push-character-count"  // 137
+                ,"hyphenation-remain-character-count"  // 138
+                                                ,"id"  // 139
+                              ,"indicate-destination"  // 140
+                               ,"initial-page-number"  // 141
+                      ,"inline-progression-dimension"  // 142
+              ,"inline-progression-dimension.minimum"  // 143
+              ,"inline-progression-dimension.optimum"  // 144
+              ,"inline-progression-dimension.maximum"  // 145
+                              ,"internal-destination"  // 146
+                                ,"intrusion-displace"  // 147
+                                     ,"keep-together"  // 148
+                         ,"keep-together.within-line"  // 149
+                       ,"keep-together.within-column"  // 150
+                         ,"keep-together.within-page"  // 151
+                                    ,"keep-with-next"  // 152
+                        ,"keep-with-next.within-line"  // 153
+                      ,"keep-with-next.within-column"  // 154
+                        ,"keep-with-next.within-page"  // 155
+                                ,"keep-with-previous"  // 156
+                    ,"keep-with-previous.within-line"  // 157
+                  ,"keep-with-previous.within-column"  // 158
+                    ,"keep-with-previous.within-page"  // 159
+                                          ,"language"  // 160
+                              ,"last-line-end-indent"  // 161
+                                  ,"leader-alignment"  // 162
+                                     ,"leader-length"  // 163
+                             ,"leader-length.minimum"  // 164
+                             ,"leader-length.optimum"  // 165
+                             ,"leader-length.maximum"  // 166
+                                    ,"leader-pattern"  // 167
+                              ,"leader-pattern-width"  // 168
+                                              ,"left"  // 169
+                                    ,"letter-spacing"  // 170
+                            ,"letter-spacing.minimum"  // 171
+                            ,"letter-spacing.optimum"  // 172
+                            ,"letter-spacing.maximum"  // 173
+                     ,"letter-spacing.conditionality"  // 174
+                         ,"letter-spacing.precedence"  // 175
+                                      ,"letter-value"  // 176
+                                ,"linefeed-treatment"  // 177
+                                       ,"line-height"  // 178
+                               ,"line-height.minimum"  // 179
+                               ,"line-height.optimum"  // 180
+                               ,"line-height.maximum"  // 181
+                        ,"line-height.conditionality"  // 182
+                            ,"line-height.precedence"  // 183
+                      ,"line-height-shift-adjustment"  // 184
+                            ,"line-stacking-strategy"  // 185
+
+                                 ,"marker-class-name"  // 186
+                                       ,"master-name"  // 187
+                                  ,"master-reference"  // 188
+                                        ,"max-height"  // 189
+                                   ,"maximum-repeats"  // 190
+                                         ,"max-width"  // 191
+                                       ,"media-usage"  // 192
+                                        ,"min-height"  // 193
+                                         ,"min-width"  // 194
+                           ,"number-columns-repeated"  // 195
+                               ,"number-rows-spanned"  // 196
+                                       ,"odd-or-even"  // 197
+                                           ,"orphans"  // 198
+                                          ,"overflow"  // 199
+
+                                     ,"padding-after"  // 200
+                              ,"padding-after.length"  // 201
+                      ,"padding-after.conditionality"  // 202
+                                    ,"padding-before"  // 203
+                             ,"padding-before.length"  // 204
+                     ,"padding-before.conditionality"  // 205
+                                       ,"padding-end"  // 206
+                                ,"padding-end.length"  // 207
+                        ,"padding-end.conditionality"  // 208
+                                     ,"padding-start"  // 209
+                              ,"padding-start.length"  // 210
+                      ,"padding-start.conditionality"  // 211
+
+                                    ,"padding-bottom"  // 212
+                                      ,"padding-left"  // 213
+                                     ,"padding-right"  // 214
+                                       ,"padding-top"  // 215
+
+                                       ,"page-height"  // 216
+                                     ,"page-position"  // 217
+                                        ,"page-width"  // 218
+                                       ,"pause-after"  // 219
+                                      ,"pause-before"  // 220
+                                             ,"pitch"  // 221
+                                       ,"pitch-range"  // 222
+                                       ,"play-during"  // 223
+                                        ,"precedence"  // 224
+               ,"provisional-distance-between-starts"  // 225
+                      ,"provisional-label-separation"  // 226
+                             ,"reference-orientation"  // 227
+                                            ,"ref-id"  // 228
+                                       ,"region-name"  // 229
+                                    ,"relative-align"  // 230
+                                 ,"relative-position"  // 231
+                                  ,"rendering-intent"  // 232
+                                 ,"retrieve-boundary"  // 233
+                               ,"retrieve-class-name"  // 234
+                                 ,"retrieve-position"  // 235
+                                          ,"richness"  // 236
+                                             ,"right"  // 237
+                                              ,"role"  // 238
+                                        ,"rule-style"  // 239
+                                    ,"rule-thickness"  // 240
+                                           ,"scaling"  // 241
+                                    ,"scaling-method"  // 242
+                                      ,"score-spaces"  // 243
+                                            ,"script"  // 244
+                                  ,"show-destination"  // 245
+                                   ,"source-document"  // 246
+
+                                       ,"space-after"  // 247
+                               ,"space-after.minimum"  // 248
+                               ,"space-after.optimum"  // 249
+                               ,"space-after.maximum"  // 250
+                        ,"space-after.conditionality"  // 251
+                            ,"space-after.precedence"  // 252
+                                      ,"space-before"  // 253
+                              ,"space-before.minimum"  // 254
+                              ,"space-before.optimum"  // 255
+                              ,"space-before.maximum"  // 256
+                       ,"space-before.conditionality"  // 257
+                           ,"space-before.precedence"  // 258
+                                         ,"space-end"  // 259
+                                 ,"space-end.minimum"  // 260
+                                 ,"space-end.optimum"  // 261
+                                 ,"space-end.maximum"  // 262
+                          ,"space-end.conditionality"  // 263
+                              ,"space-end.precedence"  // 264
+                                       ,"space-start"  // 265
+                               ,"space-start.minimum"  // 266
+                               ,"space-start.optimum"  // 267
+                               ,"space-start.maximum"  // 268
+                        ,"space-start.conditionality"  // 269
+                            ,"space-start.precedence"  // 270
+
+                                     ,"margin-bottom"  // 271
+                                       ,"margin-left"  // 272
+                                      ,"margin-right"  // 273
+                                        ,"margin-top"  // 274
+
+                                              ,"span"  // 275
+                                             ,"speak"  // 276
+                                      ,"speak-header"  // 277
+                                     ,"speak-numeral"  // 278
+                                 ,"speak-punctuation"  // 279
+                                       ,"speech-rate"  // 280
+                                               ,"src"  // 281
+                                      ,"start-indent"  // 282
+                                    ,"starting-state"  // 283
+                                        ,"starts-row"  // 284
+                                            ,"stress"  // 285
+                            ,"suppress-at-line-break"  // 286
+                                         ,"switch-to"  // 287
+                                      ,"table-layout"  // 288
+                        ,"table-omit-footer-at-break"  // 289
+                        ,"table-omit-header-at-break"  // 290
+                       ,"target-presentation-context"  // 291
+                         ,"target-processing-context"  // 292
+                                 ,"target-stylesheet"  // 293
+                                        ,"text-align"  // 294
+                                   ,"text-align-last"  // 295
+                                     ,"text-altitude"  // 296
+                                   ,"text-decoration"  // 297
+                                        ,"text-depth"  // 298
+                                       ,"text-indent"  // 299
+                                       ,"text-shadow"  // 300
+                                    ,"text-transform"  // 301
+                                               ,"top"  // 302
+                               ,"treat-as-word-space"  // 303
+                                      ,"unicode-bidi"  // 304
+           ,"usage-context-of-suppress-at-line-break"  // 305
+                                        ,"visibility"  // 306
+                                      ,"voice-family"  // 307
+                                            ,"volume"  // 308
+                              ,"white-space-collapse"  // 309
+                             ,"white-space-treatment"  // 310
+                                            ,"widows"  // 311
+                                             ,"width"  // 312
+                                      ,"word-spacing"  // 313
+                              ,"word-spacing-minimum"  // 314
+                              ,"word-spacing-optimum"  // 315
+                              ,"word-spacing-maximum"  // 316
+                       ,"word-spacing-conditionality"  // 317
+                           ,"word-spacing-precedence"  // 318
+                                       ,"wrap-option"  // 319
+                                           ,"z-index"  // 320
+    };
+
+    /**
+     * A <tt>hashMap</tt> mapping property names (the keys) to
+     * property integer indices.
+     */
+    private static final HashMap toIndex;
+    static {
+        toIndex = new HashMap(LAST_PROPERTY_INDEX + 1);
+        // Set up the toIndex Hashmap with the name of the
+        // property as a key, and the integer index as a value
+        for (int i = 0; i <= LAST_PROPERTY_INDEX; i++) {
+            if (toIndex.put(propertyNames[i],
+                                    Ints.consts.get(i)) != null) {
+                throw new RuntimeException(
+                    "Duplicate values in toIndex for key " +
+                    propertyNames[i]);
+            }
+        }
+    }
+
+    /**
+     * @param propindex <tt>int</tt> index of the FO property.
+     * @return <tt>String</tt> name of the indexd FO property.
+     * @exception PropertyException if the property index is invalid.
+     */
+    public static String getPropertyName(int propindex)
+                throws PropertyException
+    {
+        if (propindex < 0 || propindex > LAST_PROPERTY_INDEX)
+                throw new PropertyException
+                        ("getPropertyName: index is invalid: " + propindex);
+        return propertyNames[propindex];
+    }
+
+    /**
+     * Get the property index of a property name.
+     * @param propindex <tt>int</tt> index of the FO property.
+     * @return <tt>String</tt> name of the indexd FO property.
+     * @exception PropertyException if the property index is invalid.
+     */
+    public static int getPropertyIndex(String name)
+        throws PropertyException
+    {
+        Integer intg = (Integer)(toIndex.get(name));
+        if (intg == null)
+            throw new PropertyException
+                                ("Property name '" + name + "' is unknown.");
+        return intg.intValue();
+    }
+
+}
+
+ + diff --git a/src/documentation/content/design/alt.design/PropertyConsts.html b/src/documentation/content/design/alt.design/PropertyConsts.html new file mode 100644 index 000000000..23d70b014 --- /dev/null +++ b/src/documentation/content/design/alt.design/PropertyConsts.html @@ -0,0 +1,598 @@ + + + + + PropertyConsts.java + + + +
+/**
+ * $Id$
+ * <br/>Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * <br/>For details on use and redistribution please refer to the
+ * <br/>LICENSE file included with these sources.
+ *
+ * @author <a href="mailto:pbwest@powerup.com.au">Peter B. West</a>
+ * @version $Revision$ $Name$
+ */
+
+package org.apache.fop.fo;
+
+import java.lang.Character;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.BitSet;
+import java.util.StringTokenizer;
+
+import org.apache.fop.fo.FOTree;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropNames;
+import org.apache.fop.fo.properties.Property;
+import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.datatypes.Numeric;
+import org.apache.fop.datatypes.Ints;
+import org.apache.fop.datastructs.ROIntArray;
+import org.apache.fop.datastructs.ROStringArray;
+import org.apache.fop.datastructs.ROBitSet;
+import org.apache.fop.datatypes.PropertyValue;
+
+/**
+ * This class contains a number of arrays containing values indexed by the
+ * property index value, determined from the PropNames class.  These arrays
+ * provide a means of accessing information about the nature of a property
+ * through the property index value.
+ * <p>Most of these arrays are initialised piecemeal as information is
+ * required about a particular property.
+ * There are also <tt>HashMap</tt>s which encode the various sets of
+ * properties which are defined to apply to each of the Flow Objects,
+ * and a <tt>BitSet</tt> of those properties which are
+ * automatically inherited.  The <tt>HashMap</tt>s provide a convenient
+ * means of specifying the relationship between FOs and properties.
+ */
+public class PropertyConsts {
+
+    private static final String tag = "$Name$";
+    private static final String revision = "$Revision$";
+
+    private static final String packageName = "org.apache.fop.fo";
+
+    public static final PropertyConsts pconsts;
+    static {
+        try {
+            pconsts = new PropertyConsts();
+        } catch (PropertyException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    public static final PropertyConsts getPropertyConsts() {
+        return pconsts;
+    }
+
+
+    /**
+     * A Property[] array containing Property objects corresponding to each
+     * of the property indices in <tt>PropNames</tt>.
+     * Initially empty, entries are filled on demand as calls for details
+     * about individual properties are made.
+     */
+    private final Property[] properties
+                        = new Property[PropNames.LAST_PROPERTY_INDEX + 1];
+
+    /**
+     * A Class[] array containing Class objects corresponding to each of the
+     * class names in the classNames array.  Elements are set
+     * in parallel to the creation of the class names in
+     * the classNames array.  It can be indexed by the property name
+     * constants defined in this file.
+     */
+    private final Class[] classes
+                            = new Class[PropNames.LAST_PROPERTY_INDEX + 1];
+
+    /**
+     * A String[] array of the property class names.  This array is
+     * effectively 1-based, with the first element being unused.
+     * The elements of this array are set by converting the FO
+     * property names from the array PropNames.propertyNames into class
+     * names by converting the first character of every component word to
+     * upper case, and removing all punctuation characters.
+     * It can be indexed by the property name constants defined in
+     * the PropNames class.
+     */
+    private final String[] classNames
+                            = new String[PropNames.LAST_PROPERTY_INDEX + 1];
+
+    /**
+     * A HashMap whose elements are an integer index value keyed by the name
+     * of a property class.  The index value is the index of the property
+     * class name in the classNames[] array.
+     */
+    private final HashMap classToIndex
+                        = new HashMap(PropNames.LAST_PROPERTY_INDEX + 1);
+
+    /**
+     * An <tt>int[]</tt> containing the <i>inherited</i> values from the
+     * <tt>Property</tt> classes.
+     */
+    private final int[] inherited
+                            = new int[PropNames.LAST_PROPERTY_INDEX + 1];
+
+    /**
+     * A <tt>BitSet</tt> of properties which are normally inherited
+     * (strictly, not not inherited).
+     * It is defined relative to the set of all properties; i.e. the
+     * inheritability of any property can be established by testing the
+     * bit in this set that corresponds to the queried property's index.
+     * <p>The <tt>BitSet</tt> is private and is the basis for
+     * <i>inheritedProperties</i>.
+     */
+    private final BitSet inheritedprops
+                            = new BitSet(PropNames.LAST_PROPERTY_INDEX + 1);
+
+    /**
+     * An int[] array of the types of the <i>initialValue</i> field of each
+     * property.  The array is indexed by the index value constants that are
+     * defined in the PropNames class in parallel to the
+     * PropNames.propertyNames[] array.
+     */
+    private final int[] initialValueTypes
+                            = new int[PropNames.LAST_PROPERTY_INDEX + 1];
+
+    /**
+     * A <tt>PropertyValue</tt> array containing the initial values of
+     * each of the properties.
+     */
+    private final PropertyValue[] initialValues
+                    = new PropertyValue[PropNames.LAST_PROPERTY_INDEX + 1];
+
+    /**
+     * An int[] array of the values of the <i>dataTypes</i> field of each
+     * property.  The array is indexed by the index value constants that are
+     * defined in the PropNames class in parallel to the
+     * PropNames.propertyNames[] array.
+     * The array elements are set from the values of the
+     * <i>dataTypes</i> field in each property class.
+     */
+    private final int[] datatypes
+                            = new int[PropNames.LAST_PROPERTY_INDEX + 1];
+
+    /**
+     * An int[] array of the values of the <i>traitMapping</i> field of each
+     * property.  The array is indexed by the index value constants that are
+     * defined in the PropNames class in parallel to the
+     * PropNames.propertyNames[] array.
+     * The array elements are set from the values of the
+     * <i>traitMapping</i> field in each property class.
+     */
+    private final int[] traitMappings
+                            = new int[PropNames.LAST_PROPERTY_INDEX + 1];
+
+    /**
+     * Get the initial value type for a property name.
+     * @param property String name of the FO property
+     * @return int enumerated initialValueType.  These constants are defined
+     * as static final ints in this class.  Note that an undefined property
+     * name will return the constant defined as NOTYPE_IT
+     */
+    public int getInitialValueType(String property)
+                    throws PropertyException
+    {
+        // Get the property index then index into the initialvaluetypes array
+        return getInitialValueType(PropNames.getPropertyIndex(property));
+    }
+
+    /**
+     * get the initial value type for a property index.
+     * @param propindex int index of the FO property
+     * @return int enumerated initialValueType.  These constants are defined
+     * as static final ints in the Property class.
+     * @throws PropertyException
+     */
+    public int getInitialValueType(int propindex)
+            throws PropertyException
+    {
+        setupProperty(propindex);
+        //System.out.println("getInitialValueType: " + propindex + " "
+                            //+ initialValueTypes[propindex]);
+        return initialValueTypes[propindex];
+    }
+
+    /**
+     * Get the initial value <tt>PropertyValue</tt> for a given property.
+     * Note that this is a <b>raw</b> value; if it is
+     * an unresolved percentage that value will be returned.
+     * @param index - the property index.
+     * @return a <tt>PropertyValue</tt> containing the initial property
+     * value element for the indexed property.
+     * @exception <tt>PropertyException</tt>
+     */
+    public PropertyValue getInitialValue(int propindex)
+            throws PropertyException
+    {
+        if (initialValues[propindex] != null)
+            return initialValues[propindex];
+        //System.out.println("PropertyConts.getInitialValue(" + propindex
+                           //+ ") " + PropNames.getPropertyName(propindex));
+        return
+            (initialValues[propindex] =
+                    setupProperty(propindex).getInitialValue(propindex));
+    }
+
+    /**
+     * @param propindex <tt>int</tt> index of the property
+     * @param foNode the node whose properties are being constructed.
+     * @param value the <tt>PropertyValue</tt> being refined.
+     * @return <tt>PropertyValue</tt> constructed by the property's
+     * <i>refineParsing</i> method
+     * @exception <tt>PropertyException</tt>
+     */
+    public PropertyValue refineParsing
+                        (int propindex, FONode foNode, PropertyValue value)
+        throws PropertyException
+    {
+        Property property = setupProperty(propindex);
+        return property.refineParsing(propindex, foNode, value);
+    }
+
+    /**
+     * @param propindex <tt>int</tt> index of the property
+     * @param foNode the node whose properties are being constructed.
+     * @param value the <tt>PropertyValue</tt> being refined.
+     * @param nested - <tt>boolean</tt> indicating whether this method is
+     * called normally (false), or as part of another <i>refineParsing</i>
+     * method.
+     * @see #refineParsing(FOTree,PropertyValue)
+     * @return <tt>PropertyValue</tt> constructed by the property's
+     * <i>refineParsing</i> method
+     * @exception <tt>PropertyException</tt>
+     */
+    public PropertyValue refineParsing
+        (int propindex, FONode foNode, PropertyValue value, boolean isNested)
+        throws PropertyException
+    {
+        Property property = setupProperty(propindex);
+        return property.refineParsing(propindex, foNode, value, isNested);
+    }
+
+    /**
+     * Get the <tt>Numeric</tt> value corresponding to an enumerated value.
+     * @param foNode the <tt>FONode</tt> being built
+     * @param propindex int index of the FO property
+     * @param enum - the integer equivalent of the enumeration keyword.
+     * @return the <tt>Numeric</tt> result.
+     * @throws PropertyException.
+     */
+    public Numeric getMappedNumeric(FONode foNode, int propindex, int enum)
+            throws PropertyException
+    {
+        Property property = setupProperty(propindex);
+        if ((datatypes[propindex] & Property.MAPPED_LENGTH) != 0)
+            return property.getMappedLength(foNode, enum);
+        else
+            throw new PropertyException
+                ("MAPPED_LENGTH not valid in "
+                                    + PropNames.getPropertyName(propindex));
+    }
+
+    /**
+     * @param propindex int index of the FO property
+     * @return int type of inheritance for this property
+     * (See constants defined in Properties.)
+     * @throws PropertyException.
+     */
+    public int inheritance(String property) throws PropertyException {
+        return inheritance(PropNames.getPropertyIndex(property));
+    }
+
+    /**
+     * @param propindex int index of the FO property
+     * @return int type of inheritance for this property
+     * (See constants defined in Property.)
+     * @throws PropertyException.
+     */
+    public int inheritance(int propindex) throws PropertyException {
+        setupProperty(propindex);
+        return inherited[propindex];
+    }
+
+    /**
+     * @param propindex int index of the FO property
+     * @return <tt>boolean</tt> is property inherited?
+     * @throws PropertyException.
+     */
+    public boolean isInherited(int propindex) throws PropertyException {
+        Property property = setupProperty(propindex);
+        return inherited[propindex] != Property.NO;
+    }
+
+    /**
+     * @param property String name of the FO property
+     * @return <tt>boolean</tt> is property inherited?
+     * @throws PropertyException.
+     */
+    public boolean isInherited(String property) throws PropertyException {
+        return isInherited(PropNames.getPropertyIndex(property));
+    }
+
+    /**
+     * @param propindex int index of the FO property
+     * @return <tt>boolean</tt> is property a shorthand?
+     * @throws PropertyException.
+     */
+    public boolean isShorthand(int propindex) throws PropertyException {
+        Property property = setupProperty(propindex);
+        return (datatypes[propindex] & Property.SHORTHAND) != 0;
+    }
+
+    /**
+     * @param property String name of the FO property
+     * @return <tt>boolean</tt> is property a shorthand?
+     * @throws PropertyException.
+     */
+    public boolean isShorthand(String property) throws PropertyException {
+        return isShorthand(PropNames.getPropertyIndex(property));
+    }
+
+    /**
+     * @param propertyIndex int index of the FO property
+     * @return <tt>boolean</tt> is property a compound?
+     * @throws PropertyException.
+     */
+    public boolean isCompound(int propertyIndex) throws PropertyException {
+        Property property = setupProperty(propertyIndex);
+        return (datatypes[propertyIndex] & Property.COMPOUND) != 0;
+    }
+
+    /**
+     * @param property String name of the FO property
+     * @return <tt>boolean</tt> is property a compound?
+     * @throws PropertyException.
+     */
+    public boolean isCompound(String property) throws PropertyException {
+        return isCompound(PropNames.getPropertyIndex(property));
+    }
+
+    /**
+     * @param propertyIndex int index of the FO property
+     * @return <tt>int</tt> dataTypes value.
+     * @throws PropertyException.
+     */
+    public int getDataTypes(int propertyIndex) throws PropertyException {
+        Property property = setupProperty(propertyIndex);
+        return datatypes[propertyIndex];
+    }
+
+    /**
+     * @param property String name of the FO property
+     * @return <tt>int</tt> dataTypes value.
+     * @throws PropertyException.
+     */
+    public int getDataTypes(String property) throws PropertyException {
+        return getDataTypes(PropNames.getPropertyIndex(property));
+    }
+
+    /**
+     * Map the integer value of an enum into its mapped value.
+     * Only valid when the datatype of the property includes MAPPED_ENUM.
+     * <p>Generally, the path will be enumText->enumIndex->mappedEnumText.
+     * @param index <tt>int</tt> containing the enumeration index.
+     * @param enumMap an <tt>ROStringArray</tt> of the <tt>String</tt>s 
+     * with the mapped enumeration values.
+     * @return a <tt>String</tt> with the mapped enumeration text.
+     */
+    public String enumIndexToMapping(int index, ROStringArray enumMap)
+    {
+        return enumMap.get(index);
+    }
+
+    /**
+     * @param propindex <tt>int</tt> property index.
+     * @param enum <tt>String</tt> containing the enumeration text.
+     * @return <tt>int</tt> constant representing the enumeration value.
+     * @exception PropertyException
+     */
+    public int getEnumIndex(int propindex, String enum)
+                    throws PropertyException
+    {
+        Property property = setupProperty(propindex);
+        return property.getEnumIndex(enum);
+    }
+
+    /**
+     * @param propindex <tt>int</tt> property index.
+     * @param enumIndex <tt>int</tt> containing the enumeration index.
+     * @return <tt>String</tt> containing the enumeration text.
+     * @exception PropertyException
+     */
+    public String getEnumText(int propindex, int enumIndex)
+                    throws PropertyException
+    {
+        Property property = setupProperty(propindex);
+        return property.getEnumText(enumIndex);
+    }
+
+    /**
+     * Set up the details of a single property and return the
+     * <tt>Property</tt> object.  If the <tt>Property</tt> object
+     * corresponding to the property index has not been resolved before,
+     * derive the Class and Property objects, and extract certain field
+     * values from the Property.
+     * @param propindex - the <tt>int</tt> index.
+     * @return - the <tt>Property</tt> corresponding to the index.
+     * @throws <tt>PropertyException.
+     */
+    public Property setupProperty(int propindex)
+            throws PropertyException
+    {
+        String cname = "";
+        Class pclass;
+        Property property;
+
+        //System.out.println("setupProperty " + propindex + " "
+                            //+ PropNames.getPropertyName(propindex));
+        if ((property = properties[propindex]) != null) return property;
+
+        // Get the property class name
+        StringTokenizer stoke;
+        stoke = new StringTokenizer
+                            (PropNames.getPropertyName(propindex), "-.:");
+        while (stoke.hasMoreTokens()) {
+            String token = stoke.nextToken();
+            String pname = new Character(
+                                Character.toUpperCase(token.charAt(0))
+                            ).toString() + token.substring(1);
+            cname = cname + pname;
+        }
+        classNames[propindex] = cname;
+        
+        // Set up the classToIndex Hashmap with the name of the
+        // property class as a key, and the integer index as a value
+        if (classToIndex.put(cname, Ints.consts.get(propindex)) != null)
+            throw new PropertyException
+                ("Duplicate values in classToIndex for key " + cname);
+
+        // Get the class for this property name
+        String name = packageName + ".properties." + cname;
+        try {
+            //System.out.println("classes["+propindex+"] "+name);//DEBUG
+            pclass = Class.forName(name);
+            classes[propindex] = pclass;
+
+            // Instantiate the class
+            property = (Property)(pclass.newInstance());
+            properties[propindex] = property;
+            //System.out.println
+                    //("property name "
+                     //+ property.getClass().getName());
+            //System.out.println
+            //("property name " +
+            //properties[propindex].getClass().getName());
+
+            // Set inheritance value
+            if ((inherited[propindex]
+                                = pclass.getField("inherited").getInt(null))
+                    != Property.NO)
+                            inheritedprops.set(propindex);
+            // Set datatypes
+            datatypes[propindex] = pclass.getField("dataTypes").getInt(null);
+            //System.out.println("datatypes " + datatypes[propindex] + "\n"
+                           //+ Property.listDataTypes(datatypes[propindex]));
+
+            // Set initialValueTypes
+            initialValueTypes[propindex] =
+                            pclass.getField("initialValueType").getInt(null);
+            //System.out.println("initialValueType "
+                               //+ initialValueTypes[propindex]);
+
+            traitMappings[propindex] =
+                                pclass.getField("traitMapping").getInt(null);
+
+        } catch (ClassNotFoundException e) {
+            throw new PropertyException
+                    ("ClassNotFoundException" + e.getMessage());
+        } catch (IllegalAccessException e) {
+            throw new PropertyException
+                    ("IllegalAccessException" + e.getMessage());
+        } catch (InstantiationException e) {
+            throw new PropertyException
+                    ("InstantiationException" + e.getMessage());
+        }
+        catch (NoSuchFieldException e) {
+            throw new PropertyException
+                    ("NoSuchFieldException" + e.getMessage());
+        }
+
+        return property;
+    }
+
+
+    private PropertyConsts () throws PropertyException {}
+
+}
+
+ + diff --git a/src/documentation/content/design/alt.design/PropertyParser.html b/src/documentation/content/design/alt.design/PropertyParser.html new file mode 100644 index 000000000..5d242868d --- /dev/null +++ b/src/documentation/content/design/alt.design/PropertyParser.html @@ -0,0 +1,1038 @@ + + + + + PropertyParser.java + + + +
+/*
+ * $Id$
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+
+package org.apache.fop.fo.expr;
+
+import org.apache.fop.fo.PropertyConsts;
+import org.apache.fop.fo.properties.Property;
+import org.apache.fop.fo.PropNames;
+import org.apache.fop.fo.FOTree;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.expr.SystemFontFunction;
+
+import org.apache.fop.datatypes.PropertyValue;
+import org.apache.fop.datatypes.PropertyValueList;
+import org.apache.fop.datatypes.Numeric;
+import org.apache.fop.datatypes.Literal;
+import org.apache.fop.datatypes.NCName;
+import org.apache.fop.datatypes.Percentage;
+import org.apache.fop.datatypes.Ems;
+import org.apache.fop.datatypes.IntegerType;
+import org.apache.fop.datatypes.Length;
+import org.apache.fop.datatypes.Time;
+import org.apache.fop.datatypes.Frequency;
+import org.apache.fop.datatypes.Angle;
+import org.apache.fop.datatypes.Bool;
+import org.apache.fop.datatypes.Auto;
+import org.apache.fop.datatypes.None;
+import org.apache.fop.datatypes.Slash;
+import org.apache.fop.datatypes.ColorType;
+import org.apache.fop.datatypes.StringType;
+import org.apache.fop.datatypes.MimeType;
+import org.apache.fop.datatypes.UriType;
+import org.apache.fop.datatypes.indirect.Inherit;
+import org.apache.fop.datatypes.indirect.InheritedValue;
+import org.apache.fop.datatypes.indirect.FromParent;
+import org.apache.fop.datatypes.indirect.FromNearestSpecified;
+
+import java.util.HashMap;
+
+/**
+ * Class to parse XSL FO property expression.
+ * This class is heavily based on the expression parser in James Clark's
+ * XT, an XSLT processor.
+ *
+ * PropertyParser objects are re-usable.  The constructor simply creates the
+ * object.  To parse an expression, the public method <i>Parse</i> is
+ * called.
+ */
+public class PropertyParser extends PropertyTokenizer {
+
+    private static final String tag = "$Name$";
+    private static final String revision = "$Revision$";
+
+    /** The FO tree which has initiated this parser */
+    private FOTree foTree;
+    /** The FONode which has initiated this parser */
+    private FONode node;
+
+    public PropertyParser(FOTree foTree) {
+        super();
+        this.foTree = foTree;
+    }
+
+    /**
+     * Parse the property expression described in the instance variables.
+     * 
+     * <p>The <tt>PropertyValue</tt> returned by this function has the
+     * following characteristics:
+     * If the expression resolves to a single element that object is returned
+     * directly in an object which implements <PropertyValue</tt>.
+     *
+     * <p>If the expression cannot be resolved into a single object, the set
+     * to which it resolves is returned in a <tt>PropertyValueList</tt> object
+     * (which itself implements <tt>PropertyValue</tt>).
+     *
+     * <p>The <tt>PropertyValueList</tt> contains objects whose corresponding
+     * elements in the original expression were separated by <em>commas</em>.
+     *
+     * <p>Objects whose corresponding elements in the original expression
+     * were separated by spaces are composed into a sublist contained in
+     * another <tt>PropertyValueList</tt>.  If all of the elements in the
+     * expression were separated by spaces, the returned
+     * <tt>PropertyValueList</tt> will contain one element, a
+     * <tt>PropertyValueList</tt> containing objects representing each of
+     * the space-separated elements in the original expression.
+     *
+     * <p>E.g., if a <b>font-family</b> property is assigned the string
+     * <em>Palatino, New Century Schoolbook, serif</em>, the returned value
+     * will look like this:
+     * <pre>
+     * PropertyValueList(NCName('Palatino')
+     *                   PropertyValueList(NCName('New')
+     *                                     NCName('Century')
+     *                                     NCName('Schoolbook') )
+     *                   NCName('serif') )
+     * </pre>
+     * <p>If the property had been assigned the string
+     * <em>Palatino, "New Century Schoolbook", serif</em>, the returned value
+     * would look like this:
+     * <pre>
+     * PropertyValueList(NCName('Palatino')
+     *                   NCName('New Century Schoolbook')
+     *                   NCName('serif') )
+     * </pre>
+     * <p>If a <b>background-position</b> property is assigned the string
+     * <em>top center</em>, the returned value will look like this:
+     * <pre>
+     * PropertyValueList(PropertyValueList(NCName('top')
+     *                                     NCName('center') ) )
+     * </pre>
+     *
+     * <p>Note: If the property expression String is empty, a StringProperty
+     * object holding an empty String is returned.
+     * @param node - the <tt>FONode</tt> for which the property expression
+     * is being resolved.
+     * @param property - an <tt>int</tt> containing the property index.
+     * which the property expression is to be evaluated.
+     * @param expr - the specified value (attribute on the xml element).
+     * @return a PropertyValue holding the parsed result.
+     * @throws PropertyException if the "expr" cannot be parsed as a
+     * PropertyValue.
+     */
+    public PropertyValue parse(FONode node, int property, String expr)
+        throws PropertyException
+    {
+        //System.out.println("-----Entering parse:"
+        // + PropNames.getPropertyName(property) + " " + expr);
+        synchronized (this) {
+            // make sure this parser is available
+            if (getExpr() != null) // the parser is currently active
+                throw new PropertyException
+                        ("PropertyParser is currently active: " + getExpr());
+            initialize(property, expr);
+            this.node = node;
+        }
+
+        next();
+        if (currentToken == EOF)
+            // prop value is empty
+            throw new PropertyException
+                    ("No token recognized in :" + expr + ":");
+
+        PropertyValueList propList = new PropertyValueList(property);
+        while (true) {
+            PropertyValue prop = parseAdditiveExpr();
+            if (currentToken == EOF) {
+                // end of the expression - add to list and go
+                if (propList.size() != 0) {
+                    propList.add(prop);
+                    reset();
+                    return propList;
+                } else { // list is empty
+                    reset();
+                    return prop;
+                }
+            }
+            // throw away commas separating arguments.  These can occur
+            // in font-family and voice-family.  Commas are regarded here
+            // as separators of list and sublist elements.
+            // See 7.16.5 "text-shadow" in the 1.0 Recommendation for an
+            // example of sublists.
+            if (currentToken == COMMA) {
+                next();
+                propList.add(prop);
+            } else { // whitespace separates list elements; make a sublist
+                propList.add(parseSublist(prop));
+                if (currentToken == EOF) {
+                    reset();
+                    return propList;
+                }
+            }
+        }
+    }
+
+    /**
+     * <p>Parse a property values sublist - a list of whitespace separated
+     * <tt>PropertyValue</tt>s.
+     * <p>
+     * Property value expressions for various properties may contain lists
+     * of values, which may be separated by whitespace or by commas.  See,
+     * e.g., 7.6.17 "voice-family" and 7.8.2 "font-family".  The shorthands
+     * may also contain lists of elements, generally (or exclusively)
+     * whitespace separated.  7.16.5 "text-shadow" allows whitespace
+     * separated length doubles or triples to be specified for individual
+     * shadow effects, with multiple shadow effects, each separated by
+     * commmas.
+     * @param initialValue a <tt>PropertyValue</tt> to assign as the initial
+     * value of the sublist.  The detection of this value, which is
+     * whitespace separated from a subsequent value,  has been the
+     * trigger for the creation of the sublist.
+     * @return a <tt>PropertyValueList</tt> containing the sublist.  The
+     * indicatior for the end of the sublist is the end of the expression,
+     * or a comma.
+     */
+    PropertyValueList parseSublist(PropertyValue initialValue)
+        throws PropertyException
+    {
+        PropertyValueList sublist = new PropertyValueList(property);
+        sublist.add(initialValue);
+        while (true) {
+            PropertyValue prop = parseAdditiveExpr();
+            if (currentToken == EOF) {
+                // end of the expression - add to sublist and go
+                sublist.add(prop);
+                return sublist;
+            }
+            // Comma separates next element - end of sublist
+            if (currentToken == COMMA) {
+                next();
+                sublist.add(prop);
+                return sublist;
+            } else { // whitespace separates next elements; add to sublist
+                sublist.add(prop);
+            }
+        }
+    }
+
+    /**
+     * Reset the parser by resetting the tokenizer to null (or equivalent)
+     * values.
+     */
+    public void resetParser() {
+        synchronized (this) {
+            //elementsSeen = 0;
+            //restrictedValueFunctSeen = null;
+            reset();
+        }
+    }
+
+    /**
+     * Generate an arithmetic error string.
+     * @return arithmetic error message.
+     */
+    private String arithErrorStr() {
+        return "Arithmetic operator not followed by Numeric or integer: "
+                + getExpr();
+    }
+
+
+    /**
+     * Generate an function numeric argument error string.
+     * @return function numeric argument error message.
+     */
+    private String funcNumericErrorStr() {
+        return "Function requires Numeric or integer argument: "
+                + getExpr();
+    }
+
+    /**
+     * Try to parse an addition or subtraction expression and return the
+     * resulting PropertyValue.
+     */
+    private PropertyValue parseAdditiveExpr() throws PropertyException {
+        // Evaluate and put result on the operand stack
+        //System.out.println("parseAdd");
+        PropertyValue prop = parseMultiplicativeExpr();
+        PropertyValue pv;
+        outer:
+        for (; ; ) {
+            inner:
+            switch (prop.getType()) {
+            case PropertyValue.NUMERIC: {
+                switch (currentToken) {
+                case PLUS:
+                    next();
+                    pv = parseMultiplicativeExpr();
+                    switch (pv.getType()) {
+                    case PropertyValue.NUMERIC:
+                        ((Numeric)prop).add((Numeric)pv);
+                        break inner;
+                    case PropertyValue.INTEGER:
+                        ((Numeric)prop).add((double)
+                                            (((IntegerType)pv).getInt()));
+                        break inner;
+                    default:
+                        throw new PropertyException(arithErrorStr());
+                    }
+                case MINUS:
+                    next();
+                    pv = parseMultiplicativeExpr();
+                    switch (pv.getType()) {
+                    case PropertyValue.NUMERIC:
+                        ((Numeric)prop).subtract((Numeric)pv);
+                        break inner;
+                    case PropertyValue.INTEGER:
+                        ((Numeric)prop).subtract((double)
+                                             (((IntegerType)pv).getInt()));
+                        break inner;
+                    default:
+                        throw new PropertyException(arithErrorStr());
+                    }
+                default:
+                    break outer;
+                }
+            }
+            case PropertyValue.INTEGER: {
+                int intVal = ((IntegerType)prop).getInt();
+                switch (currentToken) {
+                case PLUS:
+                    next();
+                    pv = parseMultiplicativeExpr();
+                    switch (pv.getType()) {
+                    case PropertyValue.NUMERIC:
+                        prop = ((Numeric)pv).add((double)intVal);
+                        break inner;
+                    case PropertyValue.INTEGER:
+                        ((IntegerType)prop).setInt(intVal +
+                                            ((IntegerType)pv).getInt());
+                        break inner;
+                    default:
+                        throw new PropertyException(arithErrorStr());
+                    }
+                case MINUS:
+                    next();
+                    pv = parseMultiplicativeExpr();
+                    switch (pv.getType()) {
+                    case PropertyValue.NUMERIC:
+                        ((Numeric)pv).add((double)(-intVal));
+                        prop = ((Numeric)pv).negate();
+                        break inner;
+                    case PropertyValue.INTEGER:
+                        ((IntegerType)prop).setInt(intVal +
+                                            ((IntegerType)pv).getInt());
+                        break inner;
+                    default:
+                        throw new PropertyException(arithErrorStr());
+                    }
+                default:
+                    break outer;
+                }
+            }
+            default:
+                break outer;
+            }
+        }
+        return prop;
+    }
+
+    /**
+     * Try to parse a multiply, divide or modulo expression and return
+     * the resulting PropertyValue.
+     */
+    private PropertyValue parseMultiplicativeExpr() throws PropertyException {
+        //System.out.println("parseMult");
+        PropertyValue prop = parseUnaryExpr();
+        PropertyValue pv;
+        outer:
+        // Outer loop exists to handle a sequence of multiplicative operations
+        // e.g. 5 * 4 / 2
+        // break outer; will terminate the multiplicative expression parsing
+        // break inner; will look for another trailing multiplicative
+        // operator.
+        for (; ; ) {
+            inner:
+            switch (prop.getType()) {
+            case PropertyValue.NUMERIC:
+                switch (currentToken) {
+                case DIV:
+                    next();
+                    pv = parseUnaryExpr();
+                    switch (pv.getType()) {
+                    case PropertyValue.INTEGER:
+                        ((Numeric)prop).divide
+                                        ((double)(((IntegerType)pv).getInt()));
+                        break inner;
+                    case PropertyValue.NUMERIC:
+                        ((Numeric)prop).divide((Numeric)pv);
+                        break inner;
+                    default:
+                        throw new PropertyException(arithErrorStr());
+                    }
+                case MOD:
+                    next();
+                    pv = parseUnaryExpr();
+                    switch (pv.getType()) {
+                    case PropertyValue.INTEGER:
+                        ((Numeric)prop).mod
+                                        ((double)(((IntegerType)pv).getInt()));
+                        break inner;
+                    case PropertyValue.NUMERIC:
+                        ((Numeric)prop).mod((Numeric)pv);
+                        break inner;
+                    default:
+                        throw new PropertyException(arithErrorStr());
+                    }
+                case MULTIPLY:
+                    next();
+                    pv = parseUnaryExpr();
+                    switch (pv.getType()) {
+                    case PropertyValue.INTEGER:
+                        ((Numeric)prop).multiply
+                                        ((double)(((IntegerType)pv).getInt()));
+                        break inner;
+                    case PropertyValue.NUMERIC:
+                        ((Numeric)prop).multiply((Numeric)pv);
+                        break inner;
+                    default:
+                        throw new PropertyException(arithErrorStr());
+                    }
+                default:
+                    break outer;
+                }
+                // N.B. The above case cannot fall through to here
+            case PropertyValue.INTEGER:
+                // This code treats all multiplicative operations as implicit
+                // operations on doubles.  It might be reasonable to allow
+                // an integer multiply.
+                int intVal = ((IntegerType)prop).getInt();
+                switch (currentToken) {
+                case DIV:
+                    next();
+                    pv = parseUnaryExpr();
+                    switch (pv.getType()) {
+                    case PropertyValue.INTEGER:
+                        prop = new Numeric(property,
+                            (double)intVal / ((IntegerType)pv).getInt());
+                        break inner;
+                    case PropertyValue.NUMERIC:
+                        prop = (new Numeric(property, (double)intVal))
+                                                        .divide((Numeric)pv);
+                        break inner;
+                    default:
+                        throw new PropertyException(arithErrorStr());
+                    }
+                case MOD:
+                    next();
+                    pv = parseUnaryExpr();
+                    switch (pv.getType()) {
+                    case PropertyValue.INTEGER:
+                        prop = new Numeric(property,
+                                ((double)intVal) % ((IntegerType)pv).getInt());
+                        break inner;
+                    case PropertyValue.NUMERIC:
+                        prop = (new Numeric(property, (double)intVal))
+                                                        .mod((Numeric)pv);
+                        break inner;
+                    default:
+                        throw new PropertyException(arithErrorStr());
+                    }
+                case MULTIPLY:
+                    next();
+                    pv = parseUnaryExpr();
+                    switch (pv.getType()) {
+                    case PropertyValue.INTEGER:
+                        prop = new Numeric(property,
+                            ((double)intVal) * ((IntegerType)pv).getInt());
+                        break inner;
+                    case PropertyValue.NUMERIC:
+                        prop = (new Numeric(property, (double)intVal))
+                                                   .multiply((Numeric)pv);
+                        break inner;
+                    default:
+                        throw new PropertyException(arithErrorStr());
+                    }
+                default:
+                    break outer;
+                }
+            default:
+                break outer;
+            }
+        }
+        return prop;
+    }
+
+    /**
+     * Try to parse a unary minus expression and return the
+     * resulting PropertyValue.
+     */
+    private PropertyValue parseUnaryExpr() throws PropertyException {
+        //System.out.println("Unary entry");
+        if (currentToken == MINUS) {
+            next();
+            PropertyValue pv = parseUnaryExpr();
+            switch (pv.getType()) {
+            case PropertyValue.NUMERIC:
+                return ((Numeric)pv).negate();
+            case PropertyValue.INTEGER:
+                ((IntegerType)pv).setInt( -((IntegerType)pv).getInt());
+                return pv;
+            default:
+                throw new PropertyException(arithErrorStr());
+            }
+        }
+        return parsePrimaryExpr();
+    }
+
+
+    /**
+     * Checks that the current token is a right parenthesis
+     * and throws an exception if this isn't the case.
+     */
+    private final void expectRpar() throws PropertyException {
+        if (currentToken != RPAR)
+            throw new PropertyException("expected )");
+        next();
+    }
+
+    /**
+     * Try to parse a primary expression and return the
+     * resulting PropertyValue.
+     * A primary expression is either a parenthesized expression or an
+     * expression representing a primitive PropertyValue datatype, such as a
+     * string literal, an NCname, a number or a unit expression, or a
+     * function call expression.
+     */
+    private PropertyValue parsePrimaryExpr() throws PropertyException {
+        PropertyValue prop;
+        //System.out.println("Primary currentToken:" + currentToken + " "
+        //                   + currentTokenValue);
+        switch (currentToken) {
+        case LPAR:
+            next();
+            prop = parseAdditiveExpr();
+            expectRpar();
+            // Do this here, rather than breaking, because expectRpar()
+            // consumes the right parenthesis and calls next().
+            return prop;
+
+        case LITERAL:
+            prop = new Literal(property, currentTokenValue);
+            break;
+
+        case NCNAME:
+            // Interpret this in context of the property or do it later?
+            prop = new NCName(property, currentTokenValue);
+            break;
+
+        case FLOAT:
+            // Do I need to differentiate here between floats and integers?
+            prop = new Numeric
+                    (property, Double.parseDouble(currentTokenValue));
+            break;
+
+        case INTEGER:
+            prop = new IntegerType
+                    (property, Integer.parseInt(currentTokenValue));
+            break;
+
+        case PERCENT:
+            /*
+             * Generate a Percentage object with the percentage number.
+             * The constructor converts this to a straight multiplicative
+             * factor by dividing by 100.
+             */
+            prop = Percentage.makePercentage
+                    (property, Double.parseDouble(currentTokenValue));
+            break;
+
+        case ABSOLUTE_LENGTH:
+            prop = Length.makeLength(property,
+                              Double.parseDouble(currentTokenValue),
+                              currentUnit);
+            break;
+        case TIME:
+            prop = new Time(property, currentUnit,
+                            Double.parseDouble(currentTokenValue));
+            break;
+        case FREQ:
+            prop = new Frequency(property, currentUnit,
+                                 Double.parseDouble(currentTokenValue));
+            break;
+        case ANGLE:
+            prop = new Angle(property, currentUnit,
+                             Double.parseDouble(currentTokenValue));
+            break;
+        case RELATIVE_LENGTH:
+            prop = Ems.makeEms(node, property,
+                               Double.parseDouble(currentTokenValue));
+            break;
+
+        case COLORSPEC:
+            prop = new ColorType(property, currentTokenValue);
+            break;
+
+        case BOOL:
+            prop = new Bool(property, currentTokenValue);
+            break;
+
+        case AUTO:
+            prop = new Auto(property);
+            break;
+
+        case NONE:
+            prop = new None(property);
+            break;
+
+        case INHERIT:
+            prop = new Inherit(property);
+            //throw new PropertyException("INHERIT not supported");
+            break;
+
+        case URI:
+            prop = new UriType(property, currentTokenValue);
+            break;
+
+        case MIMETYPE:
+            prop = new MimeType(property, currentTokenValue);
+            break;
+
+        case SLASH:
+            prop = new Slash(property);
+            break;
+
+        case FUNCTION_LPAR: {
+            // N.B. parseArgs() invokes expectRpar at the end of argument
+            // processing, so, like LPAR processing, next() is not called
+            // and the return from this method must be premature
+            prop = null;
+            int funcType = PropertyValue.NO_TYPE;
+            String function = currentTokenValue;
+            next();
+            do {
+                // Numeric functions
+                if (function.equals("floor")) {
+                    PropertyValue[] args = parseArgs(1);
+                    switch (args[0].getType()) {
+                    case PropertyValue.INTEGER:
+                        args[0] =
+                            new Numeric
+                                (property, ((IntegerType)args[0]).getInt());
+                    case PropertyValue.NUMERIC:
+                        prop = new Numeric
+                                (property, ((Numeric)args[0]).floor());
+                        break;
+                    default:
+                        throw new PropertyException(funcNumericErrorStr());
+                    }
+                    break;
+                }
+                if (function.equals("ceiling")) {
+                    PropertyValue[] args = parseArgs(1);
+                    switch (args[0].getType()) {
+                    case PropertyValue.INTEGER:
+                        args[0] =
+                            new Numeric
+                                (property, ((IntegerType)args[0]).getInt());
+                    case PropertyValue.NUMERIC:
+                        prop = new Numeric
+                                (property, ((Numeric)args[0]).ceiling());
+                        break;
+                    default:
+                        throw new PropertyException(funcNumericErrorStr());
+                    }
+                    break;
+                }
+                if (function.equals("round")) {
+                    PropertyValue[] args = parseArgs(1);
+                    switch (args[0].getType()) {
+                    case PropertyValue.INTEGER:
+                        args[0] =
+                            new Numeric
+                                (property, ((IntegerType)args[0]).getInt());
+                    case PropertyValue.NUMERIC:
+                        prop = new Numeric
+                                (property, ((Numeric)args[0]).round());
+                        break;
+                    default:
+                        throw new PropertyException(funcNumericErrorStr());
+                    }
+                    break;
+                }
+                if (function.equals("min")) {
+                    PropertyValue[] args = parseArgs(2);
+                    switch (args[0].getType()) {
+                    case PropertyValue.INTEGER:
+                        args[0] =
+                            new Numeric
+                                (property, ((IntegerType)args[0]).getInt());
+                    case PropertyValue.NUMERIC:
+                        prop = ((Numeric)args[0]).min((Numeric)args[1]);
+                        break;
+                    default:
+                        throw new PropertyException(funcNumericErrorStr());
+                    }
+                    break;
+                }
+                if (function.equals("max")) {
+                    PropertyValue[] args = parseArgs(2);
+                    switch (args[0].getType()) {
+                    case PropertyValue.INTEGER:
+                        args[0] =
+                            new Numeric
+                                (property, ((IntegerType)args[0]).getInt());
+                    case PropertyValue.NUMERIC:
+                        prop = ((Numeric)args[0]).max((Numeric)args[1]);
+                        break;
+                    default:
+                        throw new PropertyException(funcNumericErrorStr());
+                    }
+                    break;
+                }
+                if (function.equals("abs")) {
+                    PropertyValue[] args = parseArgs(1);
+                    switch (args[0].getType()) {
+                    case PropertyValue.INTEGER:
+                        args[0] =
+                            new Numeric
+                                (property, ((IntegerType)args[0]).getInt());
+                    case PropertyValue.NUMERIC:
+                        prop = ((Numeric)args[0]).abs();
+                        break;
+                    default:
+                        throw new PropertyException(funcNumericErrorStr());
+                    }
+                    break;
+                }
+
+                // Color functions
+                if (function.equals("rgb")) {
+                    // Currently arguments must all be integers.
+                    PropertyValue[] args = parseArgs(3);
+                    switch (args[0].getType()) {
+                    case PropertyValue.INTEGER:
+                        prop = new ColorType
+                                (property, ((IntegerType)args[0]).getInt(),
+                                 ((IntegerType)args[1]).getInt(),
+                                 ((IntegerType)args[2]).getInt());
+                        break;
+                    case PropertyValue.NUMERIC:
+                        prop = new ColorType
+                                (property, ((Numeric)args[0]).asInt(),
+                                 ((Numeric)args[1]).asInt(),
+                                 ((Numeric)args[2]).asInt());
+                        break;
+                    default:
+                        throw new PropertyException(funcNumericErrorStr());
+                    }
+                    break;
+                }
+                if (function.equals("rgb-icc")) {
+                    PropertyValue[] args = parseArgs(6);
+                    throw new FunctionNotImplementedException("rgb-icc");
+                    //break;
+                }
+                if (function.equals("system-color")) {
+                    PropertyValue[] args = parseArgs(1);
+                    prop = new ColorType
+                            (property, ((StringType)args[0]).getString());
+                    break;
+                }
+
+                // Font function
+                if (function.equals("system-font")) {
+                    PropertyValue[] args = parseArgs(1, 2);
+                    if (args.length == 1) {
+                        prop = SystemFontFunction.systemFontCharacteristic
+                                (property,
+                                 ((StringType)args[0]).getString());
+                    } else {
+                        // 2 args
+                        prop = SystemFontFunction.systemFontCharacteristic
+                                (property,
+                                 ((StringType)args[0]).getString(),
+                                 ((StringType)args[1]).getString());
+                    }
+                    break;
+                }
+
+                // Property value functions
+                if (function.equals("label-end")) {
+                    PropertyValue[] args = parseArgs(0);
+                    throw new FunctionNotImplementedException("label-end");
+                    //break;
+                }
+                if (function.equals("body-start")) {
+                    PropertyValue[] args = parseArgs(0);
+                    throw new FunctionNotImplementedException("body-start");
+                    //break;
+                }
+                if (function.equals("inherited-property-value")) {
+                    int propindex = property;
+                    PropertyValue[] args = parseArgs(0, 1);
+                    if (args.length != 0)
+                        propindex = PropNames.getPropertyIndex(
+                                ((StringType)args[0]).getString());
+
+                    // If it's a compound, return an InheritedValue object
+                    if (PropertyConsts.pconsts.isCompound(propindex)) {
+                        prop = new InheritedValue(property, propindex);
+                        break;
+                    }
+                    // Is it an inherited property?
+                    if (PropertyConsts.pconsts.inheritance(propindex)
+                                                            == Property.NO)
+                        throw new PropertyException
+                                ("inherited-property-value: "
+                                 + PropNames.getPropertyName(propindex)
+                                 + " is not inherited.");
+                    // Not a compound, and inherited - try to resolve it
+                    prop = node.fromParent(property, propindex);
+                    break;
+                }
+                // N.B. see comments on classes FromNearestSpecified and
+                // FromParent for explanation of this section
+                if (function.equals("from-parent"))
+                    funcType = PropertyValue.FROM_PARENT;
+                if (function.equals("from-nearest-specified-value"))
+                    funcType = PropertyValue.FROM_NEAREST_SPECIFIED;
+                if (funcType == PropertyValue.FROM_PARENT
+                    || funcType == PropertyValue.FROM_NEAREST_SPECIFIED)
+                {
+                    // Preset the return value in case of a shorthand property
+                    switch (funcType) {
+                    case PropertyValue.FROM_PARENT:
+                        prop = new FromParent(property);
+                    case PropertyValue.FROM_NEAREST_SPECIFIED:
+                        prop = new FromNearestSpecified(property);
+                    }
+
+                    PropertyValue[] args = parseArgs(0, 1);
+                    if (args.length == 0) {
+                        if (! (PropertyConsts.pconsts.isShorthand(property)
+                           || PropertyConsts.pconsts.isCompound(property))) {
+                            // develop the function value and return it as
+                            // a property.
+                            switch (funcType) {
+                            case PropertyValue.FROM_PARENT:
+                                prop = node.fromParent(property);
+                            case PropertyValue.FROM_NEAREST_SPECIFIED:
+                                prop = node.fromNearestSpecified(property);
+                            }
+                        }
+                        // else a shorthand/compound - do nothing;
+                        // prop has been
+                        // set to the appropriate pseudo-propertyValue
+                    } else { // one argument - it must be a property name
+                        if ( ! (args[0] instanceof NCName))
+                            throw new PropertyException
+                                    (function + " function requires"
+                                     + " property name arg.");
+                        // else arg[0] is an NCName
+                        NCName ncname = (NCName)args[0];
+                        String propname = ncname.getNCName();
+                        int nameindex =
+                                PropNames.getPropertyIndex(propname);
+                        if (PropertyConsts.pconsts.isShorthand(nameindex)
+                            || PropertyConsts.pconsts.isCompound(nameindex)) {
+                            // the argument is a shorthand/compound property -
+                            // it must be the same as the property being
+                            // assigned to.
+                            // see 5.10.4 Property Value Functions
+                            if ( ! (nameindex == property))
+                                throw new PropertyException
+                                        (function +
+                                         " argument " + propname +
+                                         " does not match property " +
+                                         PropNames.getPropertyName(property));
+                            // else perform shorthand/compound processing
+                            // i.e. do nothing;
+                            // prop has been set to the correct
+                            // pseudo-propertyValue
+                        }
+                        else {   // An NCName but not a shorthand/compound
+                            // Perform normal from-? processing
+                            switch (funcType) {
+                            case PropertyValue.FROM_PARENT:
+                                prop = node.fromParent(property, nameindex);
+                            case PropertyValue.FROM_NEAREST_SPECIFIED:
+                                prop = node.fromNearestSpecified
+                                                        (property, nameindex);
+                            }
+                        }
+                    }
+                    break;
+                }
+                if (function.equals("from-table-column")) {
+                    PropertyValue[] args = parseArgs(0, 1);
+                    throw new FunctionNotImplementedException
+                            ("from-table-column");
+                    //break;
+                }
+                if (function.equals("proportional-column-width")) {
+                    PropertyValue[] args = parseArgs(1);
+                    throw new FunctionNotImplementedException
+                            ("proportional-column-width");
+                    //break;
+                }
+                if (function.equals("merge-property-values")) {
+                    PropertyValue[] args = parseArgs(0, 1);
+                    throw new FunctionNotImplementedException
+                            ("merge-property-values");
+                    //break;
+                }
+                throw new PropertyException("no such function: "
+                                                        + function);
+            } while (false);
+            return prop;
+        }
+        default:
+            throw new PropertyException("syntax error");
+        }
+        next();
+        return prop;
+    }
+
+    /**
+     * Parse a comma separated list of function arguments. Each argument
+     * may itself be an expression. This method consumes the closing right
+     * parenthesis of the argument list.
+     * @param nbArgs The number of arguments expected by the function.
+     * @return <tt>PropertyValueList</tt> of <tt>PropertyValue</tt> objects
+     * representing the arguments found.
+     * @exception PropertyException
+     */
+    PropertyValue[] parseArgs(int nbArgs) throws PropertyException {
+        return parseArgs(nbArgs, nbArgs);
+    }
+
+    /**
+     * Parse a comma separated list of function arguments. Each argument
+     * may itself be an expression. This method consumes the closing right
+     * parenthesis of the argument list.
+     * @param minArgs The minimum number of arguments expected by the function.
+     * @param maxArgs The maximum number of arguments expected by the function.
+     * @return <tt>PropertyValueList</tt> of <tt>PropertyValue</tt> objects
+     * representing the arguments found.  N.B.  The actual number of arguments
+     * returned is guaranteed to be between minArgs and maxArgs, inclusive,
+     * but the actual list of args found is terminated by the end of the
+     * array, or the first null element.
+     * @exception PropertyException
+     */
+    PropertyValue[] parseArgs(int minArgs, int maxArgs)
+        throws PropertyException
+    {
+        PropertyValue[] args = new PropertyValue[maxArgs];
+        PropertyValue prop;
+        int i = 0;
+        if (currentToken == RPAR) {
+            // No args: func()
+            next();
+        } else {
+            while (true) {
+                prop = parseAdditiveExpr();
+                if (i < maxArgs) {
+                    args[i++] = prop;
+                }
+                // ignore extra args
+                if (currentToken != COMMA)
+                    break;
+                next();
+            }
+            expectRpar();
+        }
+        if (minArgs > i || i > maxArgs) {
+            throw new PropertyException("Wrong number of args for function");
+        }
+        return args;
+    }
+
+}
+
+ + diff --git a/src/documentation/content/design/alt.design/PropertySets.html b/src/documentation/content/design/alt.design/PropertySets.html new file mode 100644 index 000000000..1f7ee5257 --- /dev/null +++ b/src/documentation/content/design/alt.design/PropertySets.html @@ -0,0 +1,419 @@ + + + + + PropertySets.java + + + +
+/**
+ * $Id$
+ * <br/>Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * <br/>For details on use and redistribution please refer to the
+ * <br/>LICENSE file included with these sources.
+ *
+ * @author <a href="mailto:pbwest@powerup.com.au">Peter B. West</a>
+ * @version $Revision$ $Name$
+ */
+
+package org.apache.fop.fo;
+
+import java.util.BitSet;
+
+import org.apache.fop.fo.PropNames;
+import org.apache.fop.datastructs.ROBitSet;
+
+/**
+ * This class contains <tt>ROBitSet</tt>s which encode the various sets of
+ * properties which are defined to apply to each of the Flow Objects.  These 
+ * <tt>ROBitSet</tt>s provide a convenient means of specifying the
+ * relationship between FOs and properties.
+ */
+public class PropertySets {
+
+    private static final String tag = "$Name$";
+    private static final String revision = "$Revision$";
+
+    private static final String packageName = "org.apache.fop.fo";
+
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Accessibility Properties</b>.
+     */
+    private static final BitSet accessibilityProps = new BitSet();
+    public static final ROBitSet accessibilitySet;
+    public static BitSet accessibilitySetClone() {
+        return (BitSet)(accessibilityProps.clone());
+    }
+
+    static {
+         accessibilityProps.set(PropNames.ROLE);       
+         accessibilityProps.set(PropNames.SOURCE_DOCUMENT);
+         accessibilitySet = new ROBitSet(accessibilityProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Absolute Position Properties</b>.
+     */
+    private static final BitSet absolutePositionProps = new BitSet();
+    public static final ROBitSet absolutePositionSet;
+    public static BitSet absolutePositionSetClone() {
+        return (BitSet)(absolutePositionProps.clone());
+    }
+
+    static {
+        absolutePositionProps.set(PropNames.ABSOLUTE_POSITION);
+        absolutePositionProps.set(PropNames.BOTTOM);
+        absolutePositionProps.set(PropNames.LEFT);
+        absolutePositionProps.set(PropNames.RIGHT);
+        absolutePositionProps.set(PropNames.TOP);
+        absolutePositionSet = new ROBitSet(absolutePositionProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Aural Properties</b>.
+     */
+    private static final BitSet auralProps = new BitSet();
+    public static final ROBitSet auralSet;
+    public static BitSet auralSetClone() {
+        return (BitSet)(auralProps.clone());
+    }
+
+    static {
+        auralProps.set(PropNames.AZIMUTH);
+        auralProps.set(PropNames.CUE_AFTER);
+        auralProps.set(PropNames.CUE_BEFORE);
+        auralProps.set(PropNames.ELEVATION);
+        auralProps.set(PropNames.PAUSE_AFTER);
+        auralProps.set(PropNames.PAUSE_BEFORE);
+        auralProps.set(PropNames.PITCH);
+        auralProps.set(PropNames.PITCH_RANGE);
+        auralProps.set(PropNames.PLAY_DURING);
+        auralProps.set(PropNames.RICHNESS);
+        auralProps.set(PropNames.SPEAK);
+        auralProps.set(PropNames.SPEAK_HEADER);
+        auralProps.set(PropNames.SPEAK_NUMERAL);
+        auralProps.set(PropNames.SPEAK_PUNCTUATION);
+        auralProps.set(PropNames.SPEECH_RATE);
+        auralProps.set(PropNames.STRESS);
+        auralProps.set(PropNames.VOICE_FAMILY);
+        auralProps.set(PropNames.VOLUME);
+        auralSet = new ROBitSet(auralProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Background Properties</b>.
+     */
+    private static final BitSet backgroundProps = new BitSet();
+    public static final ROBitSet backgroundSet;
+    public static BitSet backgroundSetClone() {
+        return (BitSet)(backgroundProps.clone());
+    }
+
+    static {
+        backgroundProps.set(PropNames.BACKGROUND);
+        backgroundProps.set(PropNames.BACKGROUND_ATTACHMENT);
+        backgroundProps.set(PropNames.BACKGROUND_COLOR);
+        backgroundProps.set(PropNames.BACKGROUND_IMAGE);
+        backgroundProps.set(PropNames.BACKGROUND_POSITION);
+        backgroundProps.set(PropNames.BACKGROUND_POSITION_HORIZONTAL);
+        backgroundProps.set(PropNames.BACKGROUND_POSITION_VERTICAL);
+        backgroundProps.set(PropNames.BACKGROUND_REPEAT);
+        backgroundSet = new ROBitSet(backgroundProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Border Properties</b>.
+     */
+    private static final BitSet borderProps = new BitSet();
+    public static final ROBitSet borderSet;
+    public static BitSet borderSetClone() {
+        return (BitSet)(borderProps.clone());
+    }
+
+    static {
+        borderProps.set(PropNames.BORDER);
+        borderProps.set(PropNames.BORDER_AFTER_COLOR);
+        borderProps.set(PropNames.BORDER_AFTER_STYLE);
+        borderProps.set(PropNames.BORDER_AFTER_WIDTH);
+        borderProps.set(PropNames.BORDER_AFTER_WIDTH_LENGTH);
+        borderProps.set(PropNames.BORDER_AFTER_WIDTH_CONDITIONALITY);
+        borderProps.set(PropNames.BORDER_BEFORE_COLOR);
+        borderProps.set(PropNames.BORDER_BEFORE_STYLE);
+        borderProps.set(PropNames.BORDER_BEFORE_WIDTH);
+        borderProps.set(PropNames.BORDER_BEFORE_WIDTH_LENGTH);
+        borderProps.set(PropNames.BORDER_BEFORE_WIDTH_CONDITIONALITY);
+        borderProps.set(PropNames.BORDER_BOTTOM);
+        borderProps.set(PropNames.BORDER_BOTTOM_COLOR);
+        borderProps.set(PropNames.BORDER_BOTTOM_STYLE);
+        borderProps.set(PropNames.BORDER_BOTTOM_WIDTH);
+        borderProps.set(PropNames.BORDER_COLOR);
+        borderProps.set(PropNames.BORDER_END_COLOR);
+        borderProps.set(PropNames.BORDER_END_STYLE);
+        borderProps.set(PropNames.BORDER_END_WIDTH);
+        borderProps.set(PropNames.BORDER_END_WIDTH_LENGTH);
+        borderProps.set(PropNames.BORDER_END_WIDTH_CONDITIONALITY);
+        borderProps.set(PropNames.BORDER_LEFT);
+        borderProps.set(PropNames.BORDER_LEFT_COLOR);
+        borderProps.set(PropNames.BORDER_LEFT_STYLE);
+        borderProps.set(PropNames.BORDER_LEFT_WIDTH);
+        borderProps.set(PropNames.BORDER_RIGHT);
+        borderProps.set(PropNames.BORDER_RIGHT_COLOR);
+        borderProps.set(PropNames.BORDER_RIGHT_STYLE);
+        borderProps.set(PropNames.BORDER_RIGHT_WIDTH);
+        borderProps.set(PropNames.BORDER_START_COLOR);
+        borderProps.set(PropNames.BORDER_START_STYLE);
+        borderProps.set(PropNames.BORDER_START_WIDTH);
+        borderProps.set(PropNames.BORDER_START_WIDTH_LENGTH);
+        borderProps.set(PropNames.BORDER_START_WIDTH_CONDITIONALITY);
+        borderProps.set(PropNames.BORDER_STYLE);
+        borderProps.set(PropNames.BORDER_TOP);
+        borderProps.set(PropNames.BORDER_TOP_COLOR);
+        borderProps.set(PropNames.BORDER_TOP_STYLE);
+        borderProps.set(PropNames.BORDER_TOP_WIDTH);
+        borderProps.set(PropNames.BORDER_WIDTH);
+        borderSet = new ROBitSet(borderProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Font Properties</b>.
+     */
+    private static final BitSet fontProps = new BitSet();
+    public static final ROBitSet fontSet;
+    public static BitSet fontSetClone() {
+        return (BitSet)(fontProps.clone());
+    }
+
+    static {
+        fontProps.set(PropNames.FONT);
+        fontProps.set(PropNames.FONT_FAMILY);
+        fontProps.set(PropNames.FONT_SELECTION_STRATEGY);
+        fontProps.set(PropNames.FONT_SIZE);
+        fontProps.set(PropNames.FONT_SIZE_ADJUST);
+        fontProps.set(PropNames.FONT_STRETCH);
+        fontProps.set(PropNames.FONT_STYLE);
+        fontProps.set(PropNames.FONT_VARIANT);
+        fontProps.set(PropNames.FONT_WEIGHT);
+        fontSet = new ROBitSet(fontProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Hyphenation Properties</b>.
+     */
+    private static final BitSet hyphenationProps = new BitSet();
+    public static final ROBitSet hyphenationSet;
+    public static BitSet hyphenationSetClone() {
+        return (BitSet)(hyphenationProps.clone());
+    }
+
+    static {
+        hyphenationProps.set(PropNames.COUNTRY);
+        hyphenationProps.set(PropNames.LANGUAGE);
+        hyphenationProps.set(PropNames.SCRIPT);
+        hyphenationProps.set(PropNames.HYPHENATE);
+        hyphenationProps.set(PropNames.HYPHENATION_CHARACTER);
+        hyphenationProps.set(PropNames.HYPHENATION_PUSH_CHARACTER_COUNT);
+        hyphenationProps.set(PropNames.HYPHENATION_REMAIN_CHARACTER_COUNT);
+        hyphenationSet = new ROBitSet(hyphenationProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Margin-Block Properties</b>.
+     */
+    private static final BitSet marginBlockProps = new BitSet();
+    public static final ROBitSet marginBlockSet;
+    public static BitSet marginBlockSetClone() {
+        return (BitSet)(marginBlockProps.clone());
+    }
+
+    static {
+        marginBlockProps.set(PropNames.MARGIN);
+        marginBlockProps.set(PropNames.MARGIN_BOTTOM);
+        marginBlockProps.set(PropNames.MARGIN_LEFT);
+        marginBlockProps.set(PropNames.MARGIN_RIGHT);
+        marginBlockProps.set(PropNames.MARGIN_TOP);
+        marginBlockSet = new ROBitSet(marginBlockProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Margin-Inline Properties</b>.
+     */
+    private static final BitSet marginInlineProps = new BitSet();
+    public static final ROBitSet marginInlineSet;
+    public static BitSet marginInlineSetClone() {
+        return (BitSet)(marginInlineProps.clone());
+    }
+
+    static {
+        marginInlineProps.set(PropNames.SPACE_END);
+        marginInlineProps.set(PropNames.SPACE_START);
+        marginInlineSet = new ROBitSet(marginInlineProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Padding Properties</b>.
+     */
+    private static final BitSet paddingProps = new BitSet();
+    public static final ROBitSet paddingSet;
+    public static BitSet paddingSetClone() {
+        return (BitSet)(paddingProps.clone());
+    }
+
+    static {
+        paddingProps.set(PropNames.PADDING);
+        paddingProps.set(PropNames.PADDING_AFTER);
+        paddingProps.set(PropNames.PADDING_AFTER_LENGTH);
+        paddingProps.set(PropNames.PADDING_AFTER_CONDITIONALITY);
+        paddingProps.set(PropNames.PADDING_BEFORE);
+        paddingProps.set(PropNames.PADDING_BEFORE_LENGTH);
+        paddingProps.set(PropNames.PADDING_BEFORE_CONDITIONALITY);
+        paddingProps.set(PropNames.PADDING_BOTTOM);
+        paddingProps.set(PropNames.PADDING_END);
+        paddingProps.set(PropNames.PADDING_END_LENGTH);
+        paddingProps.set(PropNames.PADDING_END_CONDITIONALITY);
+        paddingProps.set(PropNames.PADDING_LEFT);
+        paddingProps.set(PropNames.PADDING_RIGHT);
+        paddingProps.set(PropNames.PADDING_START);
+        paddingProps.set(PropNames.PADDING_START_LENGTH);
+        paddingProps.set(PropNames.PADDING_START_CONDITIONALITY);
+        paddingProps.set(PropNames.PADDING_TOP);
+        paddingSet = new ROBitSet(paddingProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Relative Position Properties</b>.
+     */
+    private static final BitSet relativePositionProps = new BitSet();
+    public static final ROBitSet relativePositionSet;
+    public static BitSet relativePositionSetClone() {
+        return (BitSet)(relativePositionProps.clone());
+    }
+
+    static {
+        relativePositionProps.set(PropNames.RELATIVE_POSITION);
+        relativePositionProps.set(PropNames.BOTTOM);
+        relativePositionProps.set(PropNames.LEFT);
+        relativePositionProps.set(PropNames.RIGHT);
+        relativePositionProps.set(PropNames.TOP);
+        relativePositionSet =
+                    new ROBitSet(relativePositionProps);
+    }
+    /**
+     * <tt>BitSet</tt> of the <tt>Integer</tt> objects corresponding to the
+     * constant index of each property in the set of
+     * <b>Common Table Properties</b>.
+     */
+    private static final BitSet tableProps = new BitSet();
+    public static final ROBitSet tableSet;
+    public static BitSet tableSetClone() {
+        return (BitSet)(tableProps.clone());
+    }
+
+    static {
+        tableProps.set(PropNames.BORDER_AFTER_PRECEDENCE);
+        tableProps.set(PropNames.BORDER_BEFORE_PRECEDENCE);
+        tableProps.set(PropNames.BORDER_COLLAPSE);
+        tableProps.set(PropNames.BORDER_END_PRECEDENCE);
+        tableProps.set(PropNames.BORDER_SEPARATION);
+        tableProps.set(PropNames.BORDER_SEPARATION_BLOCK_PROGRESSION_DIRECTION);
+        tableProps.set(PropNames.BORDER_SEPARATION_INLINE_PROGRESSION_DIRECTION);
+        tableProps.set(PropNames.BORDER_SPACING);
+        tableProps.set(PropNames.BORDER_START_PRECEDENCE);
+        tableProps.set(PropNames.CAPTION_SIDE);
+        tableProps.set(PropNames.COLUMN_NUMBER);
+        tableProps.set(PropNames.COLUMN_WIDTH);
+        tableProps.set(PropNames.EMPTY_CELLS);
+        tableProps.set(PropNames.ENDS_ROW);
+        tableProps.set(PropNames.NUMBER_COLUMNS_REPEATED);
+        tableProps.set(PropNames.NUMBER_COLUMNS_SPANNED);
+        tableProps.set(PropNames.NUMBER_ROWS_SPANNED);
+        tableProps.set(PropNames.STARTS_ROW);
+        tableProps.set(PropNames.TABLE_LAYOUT);
+        tableProps.set(PropNames.TABLE_OMIT_FOOTER_AT_BREAK);
+        tableProps.set(PropNames.TABLE_OMIT_HEADER_AT_BREAK);
+        tableSet = new ROBitSet(tableProps);
+    }
+
+    private PropertySets (){}
+
+}
+
+ + diff --git a/src/documentation/content/design/alt.design/PropertyTokenizer.html b/src/documentation/content/design/alt.design/PropertyTokenizer.html new file mode 100644 index 000000000..6f7622f74 --- /dev/null +++ b/src/documentation/content/design/alt.design/PropertyTokenizer.html @@ -0,0 +1,649 @@ + + + + + PropertyTokenizer.java + + + +
+/*
+ * $Id$
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+
+package org.apache.fop.fo.expr;
+
+import org.apache.fop.datatypes.Numeric;
+import org.apache.fop.datatypes.Length;
+import org.apache.fop.datatypes.Frequency;
+import org.apache.fop.datatypes.Time;
+
+/**
+ * Class to tokenize XSL FO property expression.
+ * This class is heavily based on the epxression tokenizer in James Clark's
+ * XT, an XSLT processor.
+ */
+class PropertyTokenizer {
+
+    private static final String tag = "$Name$";
+    private static final String revision = "$Revision$";
+
+    /*
+     * Maintain the numbering of this list in (X)Emacs by issuing
+     * a shell command on the region with replacement (M-1 M-|).  Use
+     * the perl command:
+     * perl -p -e 'BEGIN{$n=0};$n++ if s/= [0-9]+/= $n/'
+     *
+     * in vi, set mark `a' at the last line and
+     * !'aperl... etc
+     */
+    static final int
+                 EOF = 0
+             ,NCNAME = 1
+           ,MULTIPLY = 2
+               ,LPAR = 3
+               ,RPAR = 4
+            ,LITERAL = 5
+      ,FUNCTION_LPAR = 6
+               ,PLUS = 7
+              ,MINUS = 8
+                ,MOD = 9
+                ,DIV = 10
+              ,COMMA = 11
+            ,PERCENT = 12
+          ,COLORSPEC = 13
+              ,FLOAT = 14
+            ,INTEGER = 15
+    ,ABSOLUTE_LENGTH = 16
+    ,RELATIVE_LENGTH = 17
+               ,TIME = 18
+               ,FREQ = 19
+              ,ANGLE = 20
+            ,INHERIT = 21
+               ,AUTO = 22
+               ,NONE = 23
+               ,BOOL = 24
+                ,URI = 25
+           ,MIMETYPE = 26
+              ,SLASH = 27
+            // NO_UNIT is a transient token for internal use only.  It is
+            // never set as the end result of parsing a token.
+            ,NO_UNIT = 28
+            //,NSPREFIX = 29
+            //,WHITESPACE = 30
+                     ;
+
+    /*
+     * Absolute unit type constants
+     */
+    int currentToken = EOF;
+    String currentTokenValue = null;
+    protected int currentUnitIndex = 0;
+    protected int currentUnit;
+    protected String unitString;
+    protected String uri;
+
+    private int currentTokenStartIndex = 0;
+    private String expr = null;
+    private int exprIndex = 0;
+    private int exprLength;
+    protected int property;
+
+    protected PropertyTokenizer() {}
+
+    /**
+     * Initialize this tokenizer to tokenize the passed
+     * String as a value of the passed property.
+     * It is assumed that the subclass has made any necessary
+     * synchronization arrangements.
+     * @param property an <tt>int</tt> containing the property index.
+     * @param s The Property expression to tokenize.
+     */
+    protected void initialize(int property, String s) {
+        expr = s;
+        exprLength = s.length();
+        this.property = property;
+        //System.out.println("-----Tokenizer initialized: " + expr);
+    }
+
+    /**
+     * Reset the tokenizer to null (or equivalent) values.
+     * Synchronization is achieved in the subclass.
+     */
+    protected void reset() {
+        expr = null;
+        exprIndex = 0;
+        exprLength = 0;
+        currentToken = EOF;
+        currentTokenValue = null;
+        property = 0;
+        //System.out.println("-----Tokenizer reset.");
+    }
+
+    /**
+     * Get the current expression
+     * @return - the expression.
+     */
+    public String getExpr() {
+        return expr;
+    }
+
+    /**
+     * Return the next token in the expression string.
+     * This sets the following package visible variables:
+     * currentToken  An enumerated value identifying the recognized token
+     * currentTokenValue  A String containing the token contents
+     * currentUnit  If currentToken = ABSOLUTE_LENGTH, TIME or FREQUENCY,
+     * an enumerated value identifying the unit.
+     * @throws PropertyException If un unrecognized token is encountered.
+     */
+    void next() throws PropertyException {
+        //System.out.println("expr:" + expr + ":  exprIndex: " + exprIndex);
+        currentTokenValue = null;
+        currentTokenStartIndex = exprIndex;
+        boolean bSawDecimal;
+        for (; ; ) {
+            if (exprIndex >= exprLength) {
+                currentToken = EOF;
+                return;
+            }
+            char c = expr.charAt(exprIndex++);
+            switch (c) {
+            case ' ':
+            case '\t':
+            case '\r':
+            case '\n':
+                // Whitespace characters are valid within strings.
+                // in font family names, sequences of whitespace are
+                // compressed into a single space. (Rec 7.8.2)
+                //scanWhitespace();
+                //currentToken = WHITESPACE;
+                //currentTokenValue = expr.substring(currentTokenStartIndex,
+                //                                   exprIndex);
+                //return;
+                currentTokenStartIndex = exprIndex;
+                break;
+            case ',':
+                currentToken = COMMA;
+                return;
+            case '+':
+                currentToken = PLUS;
+                return;
+            case '-':
+                currentToken = MINUS;
+                return;
+            case '(':
+                currentToken = LPAR;
+                return;
+            case ')':
+                currentToken = RPAR;
+                return;
+            case '"':
+            case '\'':
+                exprIndex = expr.indexOf(c, exprIndex);
+                if (exprIndex < 0) {
+                    exprIndex = currentTokenStartIndex + 1;
+                    throw new PropertyException("missing quote");
+                }
+                currentTokenValue = expr.substring(currentTokenStartIndex
+                                                   + 1, exprIndex++);
+                currentToken = LITERAL;
+                return;
+            case '*':
+                currentToken = MULTIPLY;
+                return;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                scanDigits();
+                if (exprIndex < exprLength && expr.charAt(exprIndex) == '.') {
+                    exprIndex++;
+                    bSawDecimal = true;
+                    if (exprIndex < exprLength
+                            && isDigit(expr.charAt(exprIndex))) {
+                        exprIndex++;
+                        scanDigits();
+                    }
+                } else
+                    bSawDecimal = false;
+                currentUnitIndex = exprIndex;
+                if (exprIndex < exprLength && expr.charAt(exprIndex) == '%') {
+                    currentToken = PERCENT;
+                    unitString = "%";
+                    exprIndex++;
+                } else {
+                    // Check for possible unit name following number
+                    currentToken = scanUnitName();
+                    if (currentToken == NO_UNIT)
+                        currentToken = bSawDecimal ? FLOAT : INTEGER;
+                }
+                currentTokenValue = expr.substring(currentTokenStartIndex,
+                                                   currentUnitIndex);
+                return;
+
+            case '.':
+                if (exprIndex < exprLength
+                        && isDigit(expr.charAt(exprIndex))) {
+                    ++exprIndex;
+                    scanDigits();
+                    currentUnitIndex = exprIndex;
+                    if (exprIndex < exprLength
+                            && expr.charAt(exprIndex) == '%') {
+                        exprIndex++;
+                        currentToken = PERCENT;
+                    } else {
+                        // Check for possible unit name following number
+                        currentToken = scanUnitName();
+                        if (currentToken == NO_UNIT)
+                            currentToken = FLOAT;
+                    }
+                    currentTokenValue = expr.substring(currentTokenStartIndex,
+                                                       currentUnitIndex);
+                    return;
+                }
+                throw new PropertyException("illegal character '.'");
+
+            case '#':    // Start of color value
+                if (exprIndex < exprLength
+                        && isHexDigit(expr.charAt(exprIndex))) {
+                    int len;
+                    ++exprIndex;
+                    scanHexDigits();
+                    currentToken = COLORSPEC;
+                    currentTokenValue = expr.substring(currentTokenStartIndex,
+                                                       exprIndex);
+                    // Probably should have some multiple of 3 for length!
+                    len = exprIndex - currentTokenStartIndex;
+                    if (len == 4 || len == 7) return;
+                    throw new PropertyException("color not 3 or 6 hex digits");
+                } else {
+                    throw new PropertyException("illegal character '#'");
+                }
+
+            case '/':
+                currentToken = SLASH;
+                return;
+
+            default:
+                --exprIndex;
+                scanName();
+                if (exprIndex == currentTokenStartIndex)
+                    // Not a name - must be a <string>
+                    throw new PropertyException
+                            ("illegal character '"
+                             + expr.charAt(exprIndex) + "'");
+                currentTokenValue = expr.substring(currentTokenStartIndex,
+                                                   exprIndex);
+                if (currentTokenValue.equals("mod")) {
+                    currentToken = MOD;
+                   return;
+                }
+                if (currentTokenValue.equals("div")) {
+                    currentToken = DIV;
+                    return;
+                }
+                if (currentTokenValue.equals("inherit")) {
+                    currentToken = INHERIT;
+                    return;
+                }
+                if (currentTokenValue.equals("auto")) {
+                    currentToken = AUTO;
+                    return;
+                }
+                if (currentTokenValue.equals("none")) {
+                    currentToken = NONE;
+                    return;
+                }
+                if (currentTokenValue.equals("true")
+                    || currentTokenValue.equals("false")) {
+                    currentToken = BOOL;
+                    return;
+                }
+                // Quick and dirty url "parsing".  Assume that a
+                // URI-SPECIFICATION must be the only component of a
+                // property value expression
+                if (currentTokenValue.equals("url")
+                    && expr.charAt(exprIndex) == '(') {
+                    if (! scanUrl()) {
+                        throw new PropertyException
+                                ("Invalid url expression :" +
+                                 expr.substring(exprIndex));
+                    }
+                    currentToken = URI;
+                    return;
+                }
+                if (currentTokenValue.equals("content-type")) {
+                    // content-type attribute value.  Must be followed
+                    // by a mime type
+                    if (expr.charAt(exprIndex) == ':') {
+                        int mimeptr = ++exprIndex;
+                        scanMimeType();
+                        currentToken = MIMETYPE;
+                        currentTokenValue =
+                                expr.substring(mimeptr, exprIndex);
+                        return;
+                    }
+                    // else it's just a name
+                }
+                if (currentTokenValue.equals("namespace-prefix")) {
+                    // content-type attribute value.  Must be followed
+                    // by a declared namespace-prefix or null
+                    if (expr.charAt(exprIndex) == ':') {
+                        int nsptr = ++exprIndex;
+                        scanName();   // Allowed to be empty
+                        currentToken = NCNAME;
+                        currentTokenValue =
+                                expr.substring(nsptr, exprIndex);
+                        return;
+                    }
+                    // else it's just a name
+                }
+                if (followingParen()) {
+                    currentToken = FUNCTION_LPAR;
+                } else {
+                    currentToken = NCNAME;
+                }
+                return;
+            }
+        }
+    }
+
+    /**
+     * Attempt to recognize a valid UnitName token in the input expression.
+     * @return token value appropriate to UnitName: ABSOLUTE_LENGTH,
+     * RELATIVE_LENGTH or NO_UNIT.
+     * @exception PropertyException if an NCName not a UnitName recognized.
+     */
+    private int scanUnitName() throws PropertyException {
+        currentUnitIndex = exprIndex;
+        scanName();
+        if (currentUnitIndex < exprIndex) {
+            unitString = expr.substring(currentUnitIndex, exprIndex);
+            if (unitString.equals("em")) return RELATIVE_LENGTH;
+            if (unitString.equals("cm")) {
+                currentUnit = Length.CM;
+                return ABSOLUTE_LENGTH;
+            }
+            if (unitString.equals("mm")) {
+                currentUnit = Length.MM;
+                return ABSOLUTE_LENGTH;
+            }
+            if (unitString.equals("in")) {
+                currentUnit = Length.IN;
+                return ABSOLUTE_LENGTH;
+            }
+            if (unitString.equals("pt")) {
+                currentUnit = Length.PT;
+                return ABSOLUTE_LENGTH;
+            }
+            if (unitString.equals("pc")) {
+                currentUnit = Length.PC;
+                return ABSOLUTE_LENGTH;
+            }
+            if (unitString.equals("px")) {
+                currentUnit = Length.PX;
+                return ABSOLUTE_LENGTH;
+            }
+            if (unitString.equals("s")) {
+                currentUnit = Time.SEC;
+                return TIME;
+            }
+            if (unitString.equals("ms")) {
+                currentUnit = Time.MSEC;
+                return TIME;
+            }
+            if (unitString.equals("Hz")) {
+                currentUnit = Frequency.HZ;
+                return FREQ;
+            }
+            if (unitString.equals("kHz")) {
+                currentUnit = Frequency.KHZ;
+                return FREQ;
+            }
+            // Not a UnitName
+            throw new PropertyException
+                    ("NCName following a number is not a UnitName");
+        } else { // No NCName found
+            return NO_UNIT;
+        }
+    }
+
+    /**
+     * Attempt to recognize a valid NAME token in the input expression.
+     */
+    private void scanName() {
+        if (exprIndex < exprLength && isNameStartChar(expr.charAt(exprIndex)))
+            while (++exprIndex < exprLength
+                   && isNameChar(expr.charAt(exprIndex)));
+    }
+
+    /**
+     * Attempt to recognize a valid sequence of decimal digits in the
+     * input expression.
+     */
+    private void scanDigits() {
+        while (exprIndex < exprLength && isDigit(expr.charAt(exprIndex)))
+            exprIndex++;
+    }
+
+    /**
+     * Scan to the end of a sequence of whitespace characters in the
+     * input expression.
+     */
+    private void scanWhitespace() {
+        while (exprIndex < exprLength && isSpace(expr.charAt(exprIndex)))
+            exprIndex++;
+    }
+
+    /**
+     * Attempt to recognize a valid sequence of hexadecimal digits in the
+     * input expression.
+     */
+    private void scanHexDigits() {
+        while (exprIndex < exprLength && isHexDigit(expr.charAt(exprIndex)))
+            exprIndex++;
+    }
+
+    /**
+     * Attempt to recognize a mime-type.  Working definition here:
+     * NCName/NCName (NCName as recognized by scanName()).
+     */
+    private void scanMimeType() throws PropertyException {
+        int part1 = exprIndex;
+        scanName();
+        if (part1 != exprIndex) {
+            if (expr.charAt(exprIndex) == '/') {
+                int part2 = ++exprIndex;
+                scanName();
+                if (part2 != exprIndex)
+                    return;
+            }
+        }
+        throw new PropertyException("Mime type expected; found:" +
+                                    expr.substring(part1));
+    }
+
+    /**
+     * @return a boolean value indicating whether the following non-whitespace
+     * character is an opening parenthesis.
+     */
+    private boolean followingParen() {
+        for (int i = exprIndex; i < exprLength; i++) {
+            switch (expr.charAt(i)) {
+            case '(':
+                exprIndex = i + 1;
+                return true;
+            case ' ':
+            case '\r':
+            case '\n':
+            case '\t':
+                break;
+            default:
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Primitive URI extractor.  Assumes that the only contents of a
+     * URI-SPECIFICATION property type is a complete uri-specification.
+     * No checking is done on the syntactical validity of the URI.
+     * @return a boolean indicating whether the remainder of the
+     * characters form the body of a <tt>url(...)</tt> specification.
+     * As a side-effect, sets the <tt>protected</tt> field <i>uri</i>
+     * and sets <i>exprIndex</i> past the end of the expression, when
+     * returning a <tt>true</tt> value.
+     */
+    private boolean scanUrl() {
+        char ch;
+        String str = expr.substring(exprIndex).trim();
+        if (str.charAt(str.length() - 1) != ')') return false;
+        // Remove closing parenthesis and trim
+        str = str.substring(0, str.length() - 1).trim();
+        if ((ch = str.charAt(0)) == '"' || ch == '\'') {
+            if (str.charAt(str.length() - 1) != ch) return false;
+            str = str.substring(1, str.length() - 1);
+        }
+        uri = str.trim();
+        exprIndex = expr.length();
+        return true;
+    }
+
+    static private final String nameStartChars =
+        "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    static private final String nameChars = ".-0123456789";
+    static private final String digits = "0123456789";
+    static private final String hexchars = digits + "abcdefABCDEF";
+
+    /**
+     * Return a boolean value indicating whether the argument is a
+     * decimal digit (0-9).
+     * @param c The character to check
+     */
+    private static final boolean isDigit(char c) {
+        return digits.indexOf(c) >= 0;
+    }
+
+    /**
+     * Return a boolean value indicating whether the argument is a
+     * hexadecimal digit (0-9, A-F, a-f).
+     * @param c The character to check
+     */
+    private static final boolean isHexDigit(char c) {
+        return hexchars.indexOf(c) >= 0;
+    }
+
+    /**
+     * Return a boolean value indicating whether the argument is whitespace
+     * as defined by XSL (space, newline, CR, tab).
+     * @param c The character to check
+     */
+    private static final boolean isSpace(char c) {
+        switch (c) {
+        case ' ':
+        case '\r':
+        case '\n':
+        case '\t':
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Return a  boolean value indicating whether the argument is a valid name
+     * start character, ie. can start a NAME as defined by XSL.
+     * @param c The character to check
+     */
+    private static final boolean isNameStartChar(char c) {
+        return nameStartChars.indexOf(c) >= 0 || c >= 0x80;
+    }
+
+    /**
+     * Return a  boolean value indicating whether the argument is a valid name
+     * character, ie. can occur in a NAME as defined by XSL.
+     * @param c The character to check
+     */
+    private static final boolean isNameChar(char c) {
+        return nameStartChars.indexOf(c) >= 0 || nameChars.indexOf(c) >= 0
+               || c >= 0x80;
+    }
+
+}
+
+ + diff --git a/src/documentation/content/design/alt.design/ShorthandPropSets.html b/src/documentation/content/design/alt.design/ShorthandPropSets.html new file mode 100644 index 000000000..60b47a7f5 --- /dev/null +++ b/src/documentation/content/design/alt.design/ShorthandPropSets.html @@ -0,0 +1,1070 @@ + + + + + ShorthandPropSets.java + + + +
+/**
+ * $Id$
+ * <br/>Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * <br/>For details on use and redistribution please refer to the
+ * <br/>LICENSE file included with these sources.
+ *
+ * @author <a href="mailto:pbwest@powerup.com.au">Peter B. West</a>
+ * @version $Revision$ $Name$
+ */
+
+package org.apache.fop.fo;
+
+import java.lang.CloneNotSupportedException;
+
+import java.util.Set;
+import java.util.BitSet;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.datatypes.PropertyValue;
+import org.apache.fop.datatypes.PropertyValueList;
+import org.apache.fop.fo.PropNames;
+import org.apache.fop.fo.PropertyConsts;
+import org.apache.fop.datastructs.ROIntArray;
+import org.apache.fop.datastructs.ROBitSet;
+import org.apache.fop.datatypes.Ints;
+
+/**
+ * This class contains <tt>ROIntArray</tt>s which encode the various sets of
+ * properties into which the shorthand and compound properties expand, and
+ * utility methods for manipulating these expansions.
+ */
+public class ShorthandPropSets {
+
+    private static final String tag = "$Name$";
+    private static final String revision = "$Revision$";
+
+    private static final String packageName = "org.apache.fop.fo";
+
+
+    // My preference here for shorthands which expand to compound properties
+    // would be to expand only to the compound, and allow compounds to be
+    // "normally" expanded in a second step.  Unfortunately, the shorthand
+    // border-spacing expands (potentially) into both of the elements of
+    // the border-separation compound.  However, other compound expansions
+    // are defined with only a single value for the compound, so I will
+    // treat border-separation as a special case in the event that two
+    // values are provided.
+    // I''m not sure whether a shorthand specification which sets a compound
+    // property with a single top-level value should be regarded as a
+    // specification for the purposes of inheritance, but I will assume so
+    // until further notice.
+    // pbw
+
+    private static final int[] backgroundPosition = {
+        PropNames.BACKGROUND_POSITION_HORIZONTAL
+        ,PropNames.BACKGROUND_POSITION_VERTICAL
+    };
+
+    private static final int[] borderColor = {
+        PropNames.BORDER_TOP_COLOR
+        ,PropNames.BORDER_RIGHT_COLOR
+        ,PropNames.BORDER_BOTTOM_COLOR
+        ,PropNames.BORDER_LEFT_COLOR
+    };
+
+    private static final int[] borderStyle = {
+        PropNames.BORDER_TOP_STYLE
+        ,PropNames.BORDER_RIGHT_STYLE
+        ,PropNames.BORDER_BOTTOM_STYLE
+        ,PropNames.BORDER_LEFT_STYLE
+    };
+
+    private static final int[] borderWidth = {
+        PropNames.BORDER_TOP_WIDTH
+        ,PropNames.BORDER_RIGHT_WIDTH
+        ,PropNames.BORDER_BOTTOM_WIDTH
+        ,PropNames.BORDER_LEFT_WIDTH
+    };
+
+    public static final ROIntArray backgroundExpansion =
+        new ROIntArray(new int[][] {
+            new int[] {
+                PropNames.BACKGROUND_COLOR
+                ,PropNames.BACKGROUND_IMAGE
+                ,PropNames.BACKGROUND_REPEAT
+                ,PropNames.BACKGROUND_ATTACHMENT
+                ,PropNames.BACKGROUND_POSITION_HORIZONTAL
+                ,PropNames.BACKGROUND_POSITION_VERTICAL
+            }, backgroundPosition});
+
+    public static final ROIntArray backgroundPositionExpansion =
+        new ROIntArray(backgroundPosition);
+
+    public static final ROIntArray borderExpansion =
+        new ROIntArray(new int[][] { borderStyle, borderColor, borderWidth });
+
+    public static final ROIntArray borderStyleExpansion =
+        new ROIntArray(borderStyle);
+
+    public static final ROIntArray borderColorExpansion =
+        new ROIntArray(borderColor);
+
+    public static final ROIntArray borderWidthExpansion =
+        new ROIntArray(borderWidth);
+
+    public static final ROIntArray borderTopExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_TOP_STYLE
+            ,PropNames.BORDER_TOP_COLOR
+            ,PropNames.BORDER_TOP_WIDTH
+        });
+
+    public static final ROIntArray borderRightExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_RIGHT_STYLE
+            ,PropNames.BORDER_RIGHT_COLOR
+            ,PropNames.BORDER_RIGHT_WIDTH
+        });
+
+    public static final ROIntArray borderBottomExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_BOTTOM_STYLE
+            ,PropNames.BORDER_BOTTOM_COLOR
+            ,PropNames.BORDER_BOTTOM_WIDTH
+        });
+
+    public static final ROIntArray borderLeftExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_LEFT_STYLE
+            ,PropNames.BORDER_LEFT_COLOR
+            ,PropNames.BORDER_LEFT_WIDTH
+        });
+
+    /**
+     * Watch this one.  <i>border-spacing</i> is a shorthand which expands
+     * into the components of the <tt>&lt;border-separation&gt;</tt> compound
+     * property.
+     */
+    public static final ROIntArray borderSpacingExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_SEPARATION
+        });
+
+    public static final ROIntArray cueExpansion =
+        new ROIntArray(new int[] {
+            PropNames.CUE_BEFORE
+            ,PropNames.CUE_AFTER
+        });
+
+    /**
+     * Another nasty one.  <i>font</i> expands, in part, into
+     * <i>line-height</i>, which is itself a compound property with a
+     * <tt>&lt;space&gt;</tt> value.
+     */
+    public static final ROIntArray fontExpansion =
+        new ROIntArray(new int[] {
+            PropNames.FONT_FAMILY
+            ,PropNames.FONT_STYLE
+            ,PropNames.FONT_VARIANT
+            ,PropNames.FONT_WEIGHT
+            ,PropNames.FONT_SIZE
+            ,PropNames.LINE_HEIGHT
+            ,PropNames.FONT_SIZE_ADJUST
+            ,PropNames.FONT_STRETCH
+            ,PropNames.FONT_SELECTION_STRATEGY
+        });
+
+    public static final ROIntArray marginExpansion =
+        new ROIntArray(new int[] {
+            PropNames.MARGIN_TOP
+            ,PropNames.MARGIN_RIGHT
+            ,PropNames.MARGIN_BOTTOM
+            ,PropNames.MARGIN_LEFT
+        });
+
+    public static final ROIntArray paddingExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PADDING_TOP
+            ,PropNames.PADDING_RIGHT
+            ,PropNames.PADDING_BOTTOM
+            ,PropNames.PADDING_LEFT
+        });
+
+    public static final ROIntArray pageBreakAfterExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BREAK_AFTER
+            ,PropNames.KEEP_WITH_NEXT
+        });
+
+    public static final ROIntArray pageBreakBeforeExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BREAK_BEFORE
+            ,PropNames.KEEP_WITH_PREVIOUS
+        });
+
+    public static final ROIntArray pageBreakInsideExpansion =
+        new ROIntArray(new int[] {
+            PropNames.KEEP_TOGETHER
+        });
+
+    public static final ROIntArray pauseExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PAUSE_BEFORE
+            ,PropNames.PAUSE_AFTER
+        });
+
+    public static final ROIntArray positionExpansion =
+        new ROIntArray(new int[] {
+            PropNames.RELATIVE_POSITION
+            ,PropNames.ABSOLUTE_POSITION
+        });
+
+    public static final ROIntArray sizeExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PAGE_HEIGHT
+            ,PropNames.PAGE_WIDTH
+        });
+
+    public static final ROIntArray verticalAlignExpansion =
+        new ROIntArray(new int[] {
+            PropNames.ALIGNMENT_BASELINE
+            ,PropNames.ALIGNMENT_ADJUST
+            ,PropNames.BASELINE_SHIFT
+            ,PropNames.DOMINANT_BASELINE
+        });
+
+    public static final ROIntArray whiteSpaceExpansion =
+        new ROIntArray(new int[] {
+            PropNames.LINEFEED_TREATMENT
+            ,PropNames.WHITE_SPACE_COLLAPSE
+            ,PropNames.WHITE_SPACE_TREATMENT
+            ,PropNames.WRAP_OPTION
+        });
+
+    public static final ROIntArray xmlLangExpansion =
+        new ROIntArray(new int[] {
+            PropNames.COUNTRY
+            ,PropNames.LANGUAGE
+        });
+
+    /**
+     * Shorthand properties.  Where properties interact, they are listed
+     * in increasing precision.
+     */
+    private static final int[] shorthands = {
+            PropNames.BACKGROUND
+            ,PropNames.BACKGROUND_POSITION
+            ,PropNames.BORDER
+            ,PropNames.BORDER_STYLE
+            ,PropNames.BORDER_COLOR
+            ,PropNames.BORDER_WIDTH
+            ,PropNames.BORDER_TOP
+            ,PropNames.BORDER_RIGHT
+            ,PropNames.BORDER_BOTTOM
+            ,PropNames.BORDER_LEFT
+            ,PropNames.BORDER_SPACING
+            ,PropNames.CUE
+            ,PropNames.FONT
+            ,PropNames.MARGIN
+            ,PropNames.PADDING
+            ,PropNames.PAGE_BREAK_AFTER
+            ,PropNames.PAGE_BREAK_BEFORE
+            ,PropNames.PAGE_BREAK_INSIDE
+            ,PropNames.PAUSE
+            ,PropNames.POSITION
+            ,PropNames.SIZE
+            ,PropNames.VERTICAL_ALIGN
+            ,PropNames.WHITE_SPACE
+            ,PropNames.XML_LANG
+        };
+
+    /**
+     * Array of <i>ROIntArray</i><b> in same order as <i>shorthands</i></b>
+     * <i>ROIntArray</i>.
+     * If a public view of this is required, use
+     * Collections.unmodifiableList(Arrays.asList(shorthandExpansions))
+     */
+    private static final ROIntArray[] shorthandExpansions = {
+        backgroundExpansion
+        ,backgroundPositionExpansion
+        ,borderExpansion
+        ,borderStyleExpansion
+        ,borderColorExpansion
+        ,borderWidthExpansion
+        ,borderTopExpansion
+        ,borderRightExpansion
+        ,borderBottomExpansion
+        ,borderLeftExpansion
+        ,borderSpacingExpansion
+        ,cueExpansion
+        ,fontExpansion
+        ,marginExpansion
+        ,paddingExpansion
+        ,pageBreakAfterExpansion
+        ,pageBreakBeforeExpansion
+        ,pageBreakInsideExpansion
+        ,pauseExpansion
+        ,positionExpansion
+        ,sizeExpansion
+        ,verticalAlignExpansion
+        ,whiteSpaceExpansion
+        ,xmlLangExpansion
+    };
+
+    /**
+     * Map property index to shorthand array index
+     */
+    private static final HashMap shorthandMap;
+    static {
+        shorthandMap = new HashMap(shorthands.length);
+        for (int i = 0; i < shorthands.length; i++) {
+            shorthandMap.put
+                    ((Object)(Ints.consts.get(shorthands[i])), 
+                     (Object)(Ints.consts.get(i)));
+        }
+    }
+
+    /**
+     * RO Shorthand properties.
+     */
+    public static final ROIntArray roShorthands =
+        new ROIntArray(shorthands);
+
+    /**
+     * A <tt>ROBitSet</tt> of the shorthand properties.
+     */
+    public static final ROBitSet shorthandPropSet;
+    private static final BitSet shorthandpropset;
+    static {
+        shorthandpropset = new BitSet(PropNames.LAST_PROPERTY_INDEX + 1);
+        for (int i = 0; i < shorthands.length; i++)
+            shorthandpropset.set(shorthands[i]);
+        shorthandPropSet = new ROBitSet(shorthandpropset);
+    }
+
+    /**
+     * @param property <tt>int</tt> property index
+     * @return <tt>ROIntArray</tt> containing the expansion list for
+     * this shorthand.
+     * @exception <tt>PropertyException</tt> if this is not a valid
+     * shorthand property
+     */
+    public static ROIntArray getSHandExpansionSet(int property)
+        throws PropertyException
+    {
+        // Is the property of the argument a shorthand?
+        Integer sHIndex =
+                (Integer)(shorthandMap.get(Ints.consts.get(property)));
+        if (sHIndex == null) {
+            String propname = PropNames.getPropertyName(property);
+            throw new PropertyException
+                    (propname + " not a shorthand property");
+        }
+        // Get the array of indices of the properties in the
+        // expansion of this shorthand
+        return shorthandExpansions[sHIndex.intValue()];
+    }
+
+    /**
+     * Expand the shorthand property associated with the
+     * <tt>PropertyValue</tt> argument by copying the given value for each
+     * property in the expansion.  The <em>property</em> field of each
+     * <tt>PropertyValue</tt> will be set to one of the proeprties in the
+     * shorthand expansion.
+     * @param value a <tt>propertyValue</tt> whose <em>property</em> field
+     *  is assumed to be set to a shorthand property.
+     * @return <tt>PropertyValueList</tt> containing a list of
+     *  <tt>PropertyValue</tt>s, one for each property in the expansion of
+     *  the shorthand property.
+     * @exception PropertyException
+     */
+    public static PropertyValueList expandAndCopySHand(PropertyValue value)
+        throws PropertyException
+    {
+        // The property associated with this PropertyValue
+        int property = value.getProperty();
+        ROIntArray expansion = getSHandExpansionSet(property);
+        PropertyValueList list = new PropertyValueList(property);
+        return copyValueToSet(value, expansion, list);
+    }
+
+    /**
+     * Generate a list of the intial values of each property in a
+     * shorthand expansion.  Note that this will be a list of
+     * <b>references</b> to the initial values.
+     * @param foTree the <tt>FOTree</tt> for which properties are being
+     * processed
+     * @param property <tt>int</tt> property index
+     * @return <tt>PropertyValueList</tt> containing the intial value
+     * expansions for the (shorthand) property
+     * @exception <tt>PropertyException</tt>
+     */
+     /*
+      Don't do this.  Shorthands should not expand initial values, because
+      a distinction is needed between those properties which are given
+      a specified value and those which are set by normal inheritance or from
+      their initial values.  This so that fromSpecifiedValue() will work.
+
+    public static PropertyValueList initialValueSHandExpansion
+        (FOTree foTree, int property)
+        throws PropertyException
+    {
+        ROIntArray expansion = getSHandExpansionSet(property);
+        PropertyValueList list = new PropertyValueList(property);
+        for (int i = 0; i < expansion.length; i++) {
+            int expandedProp = expansion.get(i);
+            PropertyValue specified
+                    = foTree.getInitialSpecifiedValue(expandedProp);
+            list.add(specified);
+        }
+        return list;
+    }
+    */
+
+    /**
+     * Given a shorthand expansion list and a <tt>PropertyValue</tt>,
+     * override the list element corresponding to the <tt>PropertyValue</tt>.
+     * Correspondence is based on the <em>property</em> field of the
+     * <tt>PropertyValue</tt>.
+     * @param expansionList the expansion <tt>PropertyValueList</tt>
+     * @param element the overriding <tt>PropertyValue</tt>
+     * @return <tt>PropertyValueList</tt> the expansion list with the
+     *  appropriate element reset
+     * @exception <tt>PropertyException</tt>
+     */
+    public static PropertyValueList overrideSHandElement
+        (PropertyValueList expansionList, PropertyValue element)
+        throws PropertyException
+    {
+        int elementProp = element.getProperty();
+        ListIterator elements = expansionList.listIterator();
+        while (elements.hasNext()) {
+            PropertyValue next = (PropertyValue)(elements.next());
+            if (next.getProperty() == elementProp) {
+                elements.set(element);
+                return expansionList;
+            }
+        }
+        throw new PropertyException
+                ("Unmatched property " + elementProp +
+                 " in expansion list for " + expansionList.getProperty());
+    }
+
+    /**
+     * Given a shorthand expansion list and a <tt>PropertyValueList</tt>,
+     * override the expansion list elements corresponding to the elements
+     * of the <tt>PropertyValueList</tt>.
+     * Correspondence is based on the <em>property</em> field of the
+     * <tt>PropertyValue</tt>.
+     * @param expansionList the expansion <tt>PropertyValueList</tt>
+     * @param list the overriding <tt>PropertyValueList</tt>
+     * @return <tt>PropertyValueList</tt> the new expansion list with
+     *  appropriate elements reset
+     * @exception <tt>PropertyException</tt>
+     */
+    public static PropertyValueList overrideSHandElements
+        (PropertyValueList expansionList, PropertyValueList list)
+        throws PropertyException
+    {
+        // From the overriding list, form an array of PropertyValue references
+        // an array of property indices and an array of booleans,
+        int listsize = list.size();
+        Object[] listrefs = new Object[listsize];
+        int[] listprops = new int[listsize];
+        boolean[] propseen = new boolean[listsize];
+        Iterator listels = list.iterator();
+        int i = 0;
+        while (listels.hasNext()) {
+            listrefs[i] = listels.next();
+            listprops[i] = ((PropertyValue)listrefs[i]).getProperty();
+            i++;
+        }
+
+        ListIterator elements = expansionList.listIterator();
+        while (elements.hasNext()) {
+            PropertyValue next = (PropertyValue)(elements.next());
+            int expprop = next.getProperty();
+            for (i = 0; i < listsize; i++) {
+                if (expprop != listprops[i]) continue;
+                elements.set(listrefs[i]);
+                propseen[i] = true;
+            }
+        }
+        // Check for unmatched override elements
+        String unmatched = "";
+        boolean someunmatched = false;
+        for (i = 0; i < listsize; i++) {
+            if ( ! propseen[i]) {
+                someunmatched = true;
+                unmatched = unmatched + " " +
+                        PropNames.getPropertyName(listprops[i]);
+            }
+        }
+        if (someunmatched)
+            throw new PropertyException
+                ("Unmatched properties:" + unmatched +
+                 " : in expansion list for " + expansionList.getProperty());
+        return expansionList;
+    }
+
+    public static final ROIntArray blockProgressionDimensionCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BLOCK_PROGRESSION_DIMENSION_MINIMUM
+            ,PropNames.BLOCK_PROGRESSION_DIMENSION_OPTIMUM
+            ,PropNames.BLOCK_PROGRESSION_DIMENSION_MAXIMUM
+        });
+
+    public static final ROIntArray blockProgressionDimensionNonCopyExpansion =
+        new ROIntArray(new int[] {});
+
+    public static final ROIntArray borderAfterWidthCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_AFTER_WIDTH_LENGTH
+        });
+
+    public static final ROIntArray borderAfterWidthNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_AFTER_WIDTH_CONDITIONALITY
+        });
+
+    public static final ROIntArray borderBeforeWidthCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_BEFORE_WIDTH_LENGTH
+        });
+
+    public static final ROIntArray borderBeforeWidthNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_BEFORE_WIDTH_CONDITIONALITY
+        });
+
+    public static final ROIntArray borderEndWidthCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_END_WIDTH_LENGTH
+        });
+
+    public static final ROIntArray borderEndWidthNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_END_WIDTH_CONDITIONALITY
+        });
+
+    public static final ROIntArray borderStartWidthCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_START_WIDTH_LENGTH
+        });
+
+    public static final ROIntArray borderStartWidthNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_START_WIDTH_CONDITIONALITY
+        });
+
+    public static final ROIntArray borderSeparationCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.BORDER_SEPARATION_BLOCK_PROGRESSION_DIRECTION
+            ,PropNames.BORDER_SEPARATION_INLINE_PROGRESSION_DIRECTION
+        });
+
+    public static final ROIntArray borderSeparationNonCopyExpansion =
+        new ROIntArray(new int[] {});
+
+    public static final ROIntArray inlineProgressionDimensionCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.INLINE_PROGRESSION_DIMENSION_MINIMUM
+            ,PropNames.INLINE_PROGRESSION_DIMENSION_OPTIMUM
+            ,PropNames.INLINE_PROGRESSION_DIMENSION_MAXIMUM
+        });
+
+    public static final ROIntArray inlineProgressionDimensionNonCopyExpansion =
+        new ROIntArray(new int[] {});
+
+    public static final ROIntArray keepTogetherCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.KEEP_TOGETHER_WITHIN_LINE
+            ,PropNames.KEEP_TOGETHER_WITHIN_COLUMN
+            ,PropNames.KEEP_TOGETHER_WITHIN_PAGE
+        });
+
+    public static final ROIntArray keepTogetherNonCopyExpansion =
+        new ROIntArray(new int[] {});
+
+    public static final ROIntArray keepWithNextCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.KEEP_WITH_NEXT_WITHIN_LINE
+            ,PropNames.KEEP_WITH_NEXT_WITHIN_COLUMN
+            ,PropNames.KEEP_WITH_NEXT_WITHIN_PAGE
+        });
+
+    public static final ROIntArray keepWithNextNonCopyExpansion =
+        new ROIntArray(new int[] {});
+
+    public static final ROIntArray keepWithPreviousCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.KEEP_WITH_PREVIOUS_WITHIN_LINE
+            ,PropNames.KEEP_WITH_PREVIOUS_WITHIN_COLUMN
+            ,PropNames.KEEP_WITH_PREVIOUS_WITHIN_PAGE
+        });
+
+    public static final ROIntArray keepWithPreviousNonCopyExpansion =
+        new ROIntArray(new int[] {});
+
+    public static final ROIntArray leaderLengthCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.LEADER_LENGTH_MINIMUM
+            ,PropNames.LEADER_LENGTH_OPTIMUM
+            ,PropNames.LEADER_LENGTH_MAXIMUM
+        });
+
+    public static final ROIntArray leaderLengthNonCopyExpansion =
+        new ROIntArray(new int[] {});
+
+    public static final ROIntArray letterSpacingCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.LETTER_SPACING_MINIMUM
+            ,PropNames.LETTER_SPACING_OPTIMUM
+            ,PropNames.LETTER_SPACING_MAXIMUM
+        });
+
+    public static final ROIntArray letterSpacingNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.LETTER_SPACING_CONDITIONALITY
+            ,PropNames.LETTER_SPACING_PRECEDENCE
+        });
+
+    public static final ROIntArray lineHeightCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.LINE_HEIGHT_MINIMUM
+            ,PropNames.LINE_HEIGHT_OPTIMUM
+            ,PropNames.LINE_HEIGHT_MAXIMUM
+        });
+
+    public static final ROIntArray lineHeightNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.LINE_HEIGHT_CONDITIONALITY
+            ,PropNames.LINE_HEIGHT_PRECEDENCE
+        });
+
+    public static final ROIntArray paddingAfterCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PADDING_AFTER_LENGTH
+        });
+
+    public static final ROIntArray paddingAfterNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PADDING_AFTER_CONDITIONALITY
+        });
+
+    public static final ROIntArray paddingBeforeCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PADDING_BEFORE_LENGTH
+        });
+
+    public static final ROIntArray paddingBeforeNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PADDING_BEFORE_CONDITIONALITY
+        });
+
+    public static final ROIntArray paddingEndCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PADDING_END_LENGTH
+        });
+
+    public static final ROIntArray paddingEndNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PADDING_END_CONDITIONALITY
+        });
+
+    public static final ROIntArray paddingStartCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PADDING_START_LENGTH
+        });
+
+    public static final ROIntArray paddingStartNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.PADDING_START_CONDITIONALITY
+        });
+
+    public static final ROIntArray spaceAfterCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.SPACE_AFTER_MINIMUM
+            ,PropNames.SPACE_AFTER_OPTIMUM
+            ,PropNames.SPACE_AFTER_MAXIMUM
+        });
+
+    public static final ROIntArray spaceAfterNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.SPACE_AFTER_CONDITIONALITY
+            ,PropNames.SPACE_AFTER_PRECEDENCE
+        });
+
+    public static final ROIntArray spaceBeforeCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.SPACE_BEFORE_MINIMUM
+            ,PropNames.SPACE_BEFORE_OPTIMUM
+            ,PropNames.SPACE_BEFORE_MAXIMUM
+        });
+
+    public static final ROIntArray spaceBeforeNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.SPACE_BEFORE_CONDITIONALITY
+            ,PropNames.SPACE_BEFORE_PRECEDENCE
+        });
+
+    public static final ROIntArray spaceEndCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.SPACE_END_MINIMUM
+            ,PropNames.SPACE_END_OPTIMUM
+            ,PropNames.SPACE_END_MAXIMUM
+        });
+
+    public static final ROIntArray spaceEndNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.SPACE_END_CONDITIONALITY
+            ,PropNames.SPACE_END_PRECEDENCE
+        });
+
+    public static final ROIntArray spaceStartCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.SPACE_START_MINIMUM
+            ,PropNames.SPACE_START_OPTIMUM
+            ,PropNames.SPACE_START_MAXIMUM
+        });
+
+    public static final ROIntArray spaceStartNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.SPACE_START_CONDITIONALITY
+            ,PropNames.SPACE_START_PRECEDENCE
+        });
+
+    public static final ROIntArray wordSpacingCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.WORD_SPACING_MINIMUM
+            ,PropNames.WORD_SPACING_OPTIMUM
+            ,PropNames.WORD_SPACING_MAXIMUM
+        });
+
+    public static final ROIntArray wordSpacingNonCopyExpansion =
+        new ROIntArray(new int[] {
+            PropNames.WORD_SPACING_CONDITIONALITY
+            ,PropNames.WORD_SPACING_PRECEDENCE
+        });
+
+    private static final int[] compounds = {
+        PropNames.BLOCK_PROGRESSION_DIMENSION
+        ,PropNames.BORDER_AFTER_WIDTH
+        ,PropNames.BORDER_BEFORE_WIDTH
+        ,PropNames.BORDER_END_WIDTH
+        ,PropNames.BORDER_START_WIDTH
+        ,PropNames.BORDER_SEPARATION
+        ,PropNames.INLINE_PROGRESSION_DIMENSION
+        ,PropNames.KEEP_TOGETHER
+        ,PropNames.KEEP_WITH_NEXT
+        ,PropNames.KEEP_WITH_PREVIOUS
+        ,PropNames.LEADER_LENGTH
+        ,PropNames.LETTER_SPACING
+        ,PropNames.LINE_HEIGHT
+        ,PropNames.PADDING_AFTER
+        ,PropNames.PADDING_BEFORE
+        ,PropNames.PADDING_END
+        ,PropNames.PADDING_START
+        ,PropNames.SPACE_AFTER
+        ,PropNames.SPACE_BEFORE
+        ,PropNames.SPACE_END
+        ,PropNames.SPACE_START
+        ,PropNames.WORD_SPACING
+    };
+
+    /**
+     * Map property index to compound array index
+     */
+    private static final HashMap compoundMap;
+    static {
+        compoundMap = new HashMap(compounds.length);
+        for (int i = 0; i < compounds.length; i++) {
+            compoundMap.put
+                    ((Object)(Ints.consts.get(compounds[i])), 
+                     (Object)(Ints.consts.get(i)));
+        }
+    }
+
+    /**
+     * RO compound properties.
+     */
+    public static final ROIntArray roCompounds;
+    static {
+        roCompounds = new ROIntArray(compounds);
+    }
+
+    /**
+     * A <tt>ROBitSet</tt> of the compound properties.
+     */
+    public static final ROBitSet compoundPropSet;
+    private static final BitSet compoundpropset;
+
+    /**
+     * a <tt>ROBitSet of shorthand and compound properties.
+     */
+    public static final ROBitSet shorthandCompoundProps;
+    private static final BitSet shorthandcompoundprops;
+
+    static {
+        compoundpropset = new BitSet(PropNames.LAST_PROPERTY_INDEX + 1);
+        for (int i = 0; i < compounds.length; i++)
+            compoundpropset.set(compounds[i]);
+        compoundPropSet = new ROBitSet(compoundpropset);
+        shorthandcompoundprops = new BitSet();
+        shorthandcompoundprops.or(compoundpropset);
+        shorthandcompoundprops.or(shorthandpropset);
+        shorthandCompoundProps = new ROBitSet(shorthandcompoundprops);
+    }
+
+    /**
+     * Array of <i>ROIntArray</i><b> of the copy expansion properties of
+     * compounds in same order as <i>compounds</i></b>
+     * <i>ROIntArray</i>.
+     * If a public view of this is required, use
+     * Collections.unmodifiableList(Arrays.asList(compoundCopyExpansions))
+     */
+    private static final ROIntArray[] compoundCopyExpansions = {
+        blockProgressionDimensionCopyExpansion
+        ,borderAfterWidthCopyExpansion
+        ,borderBeforeWidthCopyExpansion
+        ,borderEndWidthCopyExpansion
+        ,borderStartWidthCopyExpansion
+        ,borderSeparationCopyExpansion
+        ,inlineProgressionDimensionCopyExpansion
+        ,keepTogetherCopyExpansion
+        ,keepWithNextCopyExpansion
+        ,keepWithPreviousCopyExpansion
+        ,leaderLengthCopyExpansion
+        ,letterSpacingCopyExpansion
+        ,lineHeightCopyExpansion
+        ,paddingAfterCopyExpansion
+        ,paddingBeforeCopyExpansion
+        ,paddingEndCopyExpansion
+        ,paddingStartCopyExpansion
+        ,spaceAfterCopyExpansion
+        ,spaceBeforeCopyExpansion
+        ,spaceEndCopyExpansion
+        ,spaceStartCopyExpansion
+        ,wordSpacingCopyExpansion
+    };
+
+    /**
+     * Array of <i>ROIntArray</i><b> of the non-copy expansion properties of
+     * compounds in same order as <i>compounds</i></b>
+     * <i>ROIntArray</i>.
+     * If a public view of this is required, use
+     * Collections.unmodifiableList(Arrays.asList(compoundNonCopyExpansions))
+     */
+    private static final ROIntArray[] compoundNonCopyExpansions = {
+        blockProgressionDimensionNonCopyExpansion
+        ,borderAfterWidthNonCopyExpansion
+        ,borderBeforeWidthNonCopyExpansion
+        ,borderEndWidthNonCopyExpansion
+        ,borderStartWidthNonCopyExpansion
+        ,borderSeparationNonCopyExpansion
+        ,inlineProgressionDimensionNonCopyExpansion
+        ,keepTogetherNonCopyExpansion
+        ,keepWithNextNonCopyExpansion
+        ,keepWithPreviousNonCopyExpansion
+        ,leaderLengthNonCopyExpansion
+        ,letterSpacingNonCopyExpansion
+        ,lineHeightNonCopyExpansion
+        ,paddingAfterNonCopyExpansion
+        ,paddingBeforeNonCopyExpansion
+        ,paddingEndNonCopyExpansion
+        ,paddingStartNonCopyExpansion
+        ,spaceAfterNonCopyExpansion
+        ,spaceBeforeNonCopyExpansion
+        ,spaceEndNonCopyExpansion
+        ,spaceStartNonCopyExpansion
+        ,wordSpacingNonCopyExpansion
+    };
+
+    /**
+     * Expand the <tt>PropertyValue</tt> assigned to a compound property
+     * into <tt>propertyValues</tt> for the individual property components.
+     * N.B. This method assumes that the set of expansion properties is
+     * comprised of a copy and a non-copy set.  For example, &lt;space&gt;
+     * compounds have a copy set of .minimum, .optimum and .maximum, and a
+     * non-copy set of .precedence and .conditionality. For each element of
+     * the copy set, the given value is cloned.  For each member of the
+     * non-copy set, a reference to the initial value is taken.
+     * @param foTree - the <tt>FOTree</tt> for which properties are being
+     * developed.
+     * @param value - the <tt>PropertyValue</tt> to be cloned for the copy
+     * set members.
+     * @return a <tt>PropertyValueList</tt> containing the copy set
+     * expansions followed by the non-copy set expansions, in the order
+     * they are defined in appropriate <tt>ROIntArray</tt>s in this class.
+     */
+    public static PropertyValueList expandCompoundProperty
+                                        (FOTree foTree, PropertyValue value)
+        throws PropertyException
+    {
+        int property = value.getProperty();
+        Integer compoundX =
+                    (Integer)(compoundMap.get(Ints.consts.get(property)));
+        if (compoundX == null)
+            throw new PropertyException
+                (PropNames.getPropertyName(property) + " (" + property + ") "
+                + " is not a compound property.");
+        int compoundIdx = compoundX.intValue();
+        PropertyValueList list = new PropertyValueList(property);
+        ROIntArray expansion;
+        // Expand the copy components
+        list = copyValueToSet
+                        (value, compoundCopyExpansions[compoundIdx], list);
+        // Expand the non-copy components
+        return initialValueCompoundExpansion
+                    (foTree, compoundNonCopyExpansions[compoundIdx], list);
+    }
+
+    /**
+     * Clone the given property value for each property in the given
+     * expansion set.  Append the new property values to the given list.
+     * @param value - the property value to clone.
+     * @param expansionSet - the set of indices of the expansion properties.
+     * @param list - the list to which to append the expansion elements.
+     * @return the original <tt>PropertyValueList</tt> containing the
+     * appended expansions.
+     * @exception <tt>PropertyException</tt>
+     */
+    private static PropertyValueList copyValueToSet(PropertyValue value,
+                            ROIntArray expansionSet, PropertyValueList list)
+        throws PropertyException
+    {
+        for (int i = 0; i < expansionSet.length; i++) {
+            int expandedProp = expansionSet.get(i);
+            PropertyValue expandedPropValue;
+            //   The PropertyValue must be cloneable
+            // The property associated with each PV in the expansion will
+            // necessarily be different.
+            try {
+                expandedPropValue = (PropertyValue)(value.clone());
+            } catch (CloneNotSupportedException e) {
+                throw new PropertyException(e.getMessage());
+            }
+
+            expandedPropValue.setProperty(expandedProp);
+            list.add(expandedPropValue);
+        }
+        return list;
+    }
+
+    /**
+     * Append the initial values of each non-copy property in a
+     * compound expansion to a list.  Note that these elements will be
+     * <b>references</b> to the initial values. Note also that, in the
+     * expansion of a compound value, the initial value comonents are
+     * regarded as having been specified.
+     * @param foTree - the <tt>FOTree</tt> of the node whose properties are
+     * being processed.
+     * @param expansion - the set of indices of the expansion properties.
+     * @param list - the list to which to append the expansion elements.
+     * @return the original <tt>PropertyValueList</tt> containing the
+     * appended initial value expansions for the (compound) property.
+     * @exception <tt>PropertyException</tt>
+     */
+    public static PropertyValueList initialValueCompoundExpansion
+                (FOTree foTree, ROIntArray expansion, PropertyValueList list)
+        throws PropertyException
+    {
+        for (int i = 0; i < expansion.length; i++) {
+            int expandedProp = expansion.get(i);
+            PropertyValue specified
+                    = PropertyConsts.pconsts.getInitialValue(expandedProp);
+            list.add(specified);
+        }
+        return list;
+    }
+
+    private ShorthandPropSets (){}
+
+}
+
+ +