From: Peter Bernard West Date: Tue, 24 Dec 2002 01:24:10 +0000 (+0000) Subject: Code documentation X-Git-Tag: Alt-Design-integration-base~219 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=61c3ccb3d407e59869cdc80904aa700736fc773c;p=xmlgraphics-fop.git Code documentation git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@195797 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/design/alt.design/properties/AutoRestore.html b/src/documentation/content/design/alt.design/properties/AutoRestore.html new file mode 100644 index 000000000..f730f5e9e --- /dev/null +++ b/src/documentation/content/design/alt.design/properties/AutoRestore.html @@ -0,0 +1,76 @@ + + + + + AutoRestore.java + + + +
+package org.apache.fop.fo.properties;
+
+import org.apache.fop.fo.properties.Property;
+import org.apache.fop.fo.PropNames;
+import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.datatypes.PropertyValue;
+import org.apache.fop.datatypes.Bool;
+
+public class AutoRestore extends Property  {
+    public static final int dataTypes = BOOL;
+    public static final int traitMapping = ACTION;
+    public static final int initialValueType = BOOL_IT;
+    public PropertyValue getInitialValue(int property)
+	throws PropertyException
+    {
+	return new Bool(PropNames.AUTO_RESTORE, true);
+    }
+    public static final int inherited = COMPUTED;
+}
+
+
+ + diff --git a/src/documentation/content/design/alt.design/properties/Character.html b/src/documentation/content/design/alt.design/properties/Character.html new file mode 100644 index 000000000..891a9b35f --- /dev/null +++ b/src/documentation/content/design/alt.design/properties/Character.html @@ -0,0 +1,68 @@ + + + + + Character.java + + + +
+package org.apache.fop.fo.properties;
+
+import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.fo.properties.Property;
+
+public class Character extends Property  {
+    public static final int dataTypes = CHARACTER_T;
+    public static final int traitMapping = FORMATTING;
+    public static final int initialValueType = NOTYPE_IT;
+    public static final int inherited = NO;
+}
+
+
+ + diff --git a/src/documentation/content/design/alt.design/properties/Property.html b/src/documentation/content/design/alt.design/properties/Property.html new file mode 100644 index 000000000..ef2cb80cd --- /dev/null +++ b/src/documentation/content/design/alt.design/properties/Property.html @@ -0,0 +1,926 @@ + + + + + Property.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 $Revision$ $Name$
+ */
+
+package org.apache.fop.fo.properties;
+
+import java.lang.Class;
+import java.lang.reflect.Method;
+
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.LinkedList;
+import java.util.Collections;
+
+import org.apache.fop.messaging.MessageHandler;
+
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropNames;
+import org.apache.fop.fo.PropertyConsts;
+import org.apache.fop.fo.ShorthandPropSets;
+import org.apache.fop.fo.FOTree;
+import org.apache.fop.fo.FOPropertySets;
+import org.apache.fop.datatypes.PropertyValue;
+import org.apache.fop.datatypes.AbstractPropertyValue;
+import org.apache.fop.datatypes.PropertyValueList;
+import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.fo.expr.PropertyNotImplementedException;
+import org.apache.fop.fo.expr.SystemFontFunction;
+import org.apache.fop.datastructs.ROStringArray;
+import org.apache.fop.datastructs.ROIntArray;
+import org.apache.fop.datatypes.Ints;
+import org.apache.fop.datatypes.NoType;
+import org.apache.fop.datatypes.StringType;
+import org.apache.fop.datatypes.NCName;
+import org.apache.fop.datatypes.CountryType;
+import org.apache.fop.datatypes.LanguageType;
+import org.apache.fop.datatypes.ScriptType;
+import org.apache.fop.datatypes.UriType;
+import org.apache.fop.datatypes.MimeType;
+import org.apache.fop.datatypes.Length;
+import org.apache.fop.datatypes.Ems;
+import org.apache.fop.datatypes.Percentage;
+import org.apache.fop.datatypes.Angle;
+import org.apache.fop.datatypes.EnumType;
+import org.apache.fop.datatypes.MappedNumeric;
+import org.apache.fop.datatypes.IntegerType;
+import org.apache.fop.datatypes.Numeric;
+import org.apache.fop.datatypes.Bool;
+import org.apache.fop.datatypes.Literal;
+import org.apache.fop.datatypes.Auto;
+import org.apache.fop.datatypes.None;
+import org.apache.fop.datatypes.ColorType;
+import org.apache.fop.datatypes.FontFamilySet;
+import org.apache.fop.datatypes.TextDecorations;
+import org.apache.fop.datatypes.TextDecorator;
+import org.apache.fop.datatypes.ShadowEffect;
+import org.apache.fop.datatypes.Slash;
+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;
+
+/**
+ * Parent class for all of the individual property classes.  It also contains
+ * sets of integer constants for various types of data.
+ */
+
+public /*abstract*/ class Property {
+
+    private static final String tag = "$Name$";
+    private static final String revision = "$Revision$";
+
+    /*
+     * The list of property data types.  These are used to form a bitmap of
+     * the property data types that are valid for values of each of the
+     * properties.
+     *
+     * Maintain the following list by
+     * in XEmacs:
+     *  set the region to cover the list, EXCLUDING the final (-ve) value
+     *  M-1 M-| followed by the command
+     * perl -p -e 'BEGIN{$n=0;$n2=0};$n2=2**$n,$n++ if s/= [0-9]+/= $n2/'
+     * in vi:
+     *  set a mark (ma) at the end of the list but one.
+     * Go to the beginning and
+     *  !'aperl -p -e ... etc
+     *
+     * N.B. The maximum value that can be handled in this way is
+     * 2^30 or 1073741824.  The -ve value is the equivalent of 2^31.
+     */
+    /**
+     * Constant specifying a property data type or types.
+     */
+
+    public static final int
+                         NOTYPE = 0
+                       ,INTEGER = 1
+                         ,FLOAT = 2
+                        ,LENGTH = 4
+                         ,ANGLE = 8
+                    ,PERCENTAGE = 16
+                   ,CHARACTER_T = 32
+                       ,LITERAL = 64
+                        ,NCNAME = 128
+                       ,COLOR_T = 256
+                     ,COUNTRY_T = 512
+                    ,LANGUAGE_T = 1024
+                      ,SCRIPT_T = 2048
+             ,URI_SPECIFICATION = 4096
+                          ,TIME = 8192
+                     ,FREQUENCY = 16384
+    // Pseudotypes
+                          ,BOOL = 32768
+                       ,INHERIT = 65536
+                          ,ENUM = 131072
+                 ,MAPPED_LENGTH = 262144
+                     ,SHORTHAND = 524288
+                       ,COMPLEX = 1048576
+                          ,AUTO = 2097152
+                          ,NONE = 4194304
+                         ,AURAL = 8388608
+    // Color plus transparent
+                   ,COLOR_TRANS = 16777216
+                      ,MIMETYPE = 33554432
+                       ,FONTSET = 67108864
+                      ,COMPOUND = 134217728
+    //                   ,SPARE = 268435456
+    //                   ,SPARE = 536870912
+    //                   ,SPARE = 1073741824
+    //                   ,SPARE = -2147483648
+
+    // A number of questions are unresolved about the interaction of
+    // complex parsing, property expression parsing & property validation.
+    // At this time (2002/07/03) it looks as though the refineParsing() method
+    // will take full validation responsibility, so it will not be
+    // necessary to specify any individual datatypes besides COMPLEX in the
+    // property dataTypes field.  This renders some such specifications
+    // redundant.  On the other hand, if such individual datatype validation
+    // becomes necessary, the datatype settings for properties with COMPLEX
+    // will have to be adjusted.  pbw
+
+                        ,NUMBER = FLOAT | INTEGER
+                     ,ENUM_TYPE = ENUM | MAPPED_LENGTH
+                        ,STRING = LITERAL | NCNAME
+                     ,HYPH_TYPE = COUNTRY_T | LANGUAGE_T | SCRIPT_T
+                     ,NAME_TYPE = NCNAME | HYPH_TYPE | ENUM_TYPE
+                   ,STRING_TYPE = STRING | NAME_TYPE
+                      ,ANY_TYPE = ~0
+                                ;
+
+    /** Constant specifying an initial data type. */
+    public static final int
+                      NOTYPE_IT = 0
+                    ,INTEGER_IT = 1
+                     ,NUMBER_IT = 2
+                     ,LENGTH_IT = 4
+                      ,ANGLE_IT = 8
+                 ,PERCENTAGE_IT = 16
+                  ,CHARACTER_IT = 32
+                    ,LITERAL_IT = 64
+                     ,NCNAME_IT = 128
+                      ,COLOR_IT = 256
+                    ,COUNTRY_IT = 512
+          ,URI_SPECIFICATION_IT = 1024
+                       ,BOOL_IT = 2048
+                       ,ENUM_IT = 4096
+                       ,AUTO_IT = 8192
+                       ,NONE_IT = 16384
+                      ,AURAL_IT = 32768
+            ,TEXT_DECORATION_IT = 65536
+  // Unused         ,FONTSET_IT = 131072
+                                ;
+
+    /**
+     * Bitmap set of initial data types for which getInitialType() must be
+     * overriden.
+     */
+    public static final int
+            USE_GET_IT_FUNCTION = //NOTYPE_IT performed in Property
+                                    INTEGER_IT
+                                  | NUMBER_IT
+                                  | LENGTH_IT
+                                  | ANGLE_IT
+                                  | PERCENTAGE_IT
+                                  | CHARACTER_IT
+                                  | LITERAL_IT
+                                  | NCNAME_IT
+                                  | COLOR_IT
+                                  | COUNTRY_IT
+                                  | URI_SPECIFICATION_IT
+                                  | BOOL_IT
+                                  | ENUM_IT
+                                  //AUTO_IT  performed in Property
+                                  //NONE_IT  performed in Property
+                                  //AURAL_IT  performed in Property
+                                  | TEXT_DECORATION_IT
+                              ;
+
+    /** Constant specifying mapping of property to trait. */
+    public static final int
+                       NO_TRAIT = 0
+                     ,RENDERING = 1
+                    ,DISAPPEARS = 2
+                 ,SHORTHAND_MAP = 4
+                        ,REFINE = 8
+                    ,FORMATTING = 16
+                 ,SPECIFICATION = 32
+                     ,NEW_TRAIT = 64
+                ,FONT_SELECTION = 128
+                  ,VALUE_CHANGE = 256
+                     ,REFERENCE = 512
+                        ,ACTION = 1024
+                         ,MAGIC = 2048
+                              ;
+
+    /*
+     * Constant specifying inheritance type.  Special cases (only line-height
+     * specified as a &lt;number&gt;, so far) must be handled close to the
+     * usage point of the property.  For line-height, the number is retained
+     * as the specified and as the computed property value.  Because the
+     * current font-size will always be present in the property set for any
+     * FONode which requires line-height, the actual length value of the
+     * line-height can always be calculated at the point of application.
+     */
+    /** Constant specifying inheritance type.  */
+    public static final int
+                             NO = 0
+                      ,COMPUTED = 1
+                              ;
+
+    public static final int dataTypes = NOTYPE;
+    public static final int initialValueType = NOTYPE_IT;
+    public static final int inherited = NO;
+
+    public static Map enumHash = null;
+
+    public Property() {}
+
+    /**
+     * Form a string representation of bitmap of datatypes.
+     * @param datatypes - a bitmap of datatype(s).
+     * @return <tt>String</tt> containing a list of text names of datatypes
+     * found in the bitmap.  Individual names are enclosed in angle brackets
+     * and separated by a vertical bar.  Psuedo-datatypes are in upper case.
+     * @exception PropertyException if no matches are found.
+     */
+    public static String listDataTypes(int datatypes)
+                    throws PropertyException
+    {
+        String typeNames = "";
+        if ((datatypes & ANY_TYPE) == ANY_TYPE) return "<ALL-TYPES>";
+        if ((datatypes & INTEGER) != 0) typeNames += "<integer>|";
+        if ((datatypes & NUMBER) != 0) typeNames += "<number>|";
+        if ((datatypes & LENGTH) != 0) typeNames += "<length>|";
+        if ((datatypes & ANGLE) != 0) typeNames += "<angle>|";
+        if ((datatypes & PERCENTAGE) != 0) typeNames += "<percentage>|";
+        if ((datatypes & CHARACTER_T) != 0) typeNames += "<character>|";
+        if ((datatypes & STRING) != 0) typeNames += "<string>|";
+        if ((datatypes & NCNAME) != 0) typeNames += "<ncname>|";
+        if ((datatypes & COLOR_T) != 0) typeNames += "<color>|";
+        if ((datatypes & COUNTRY_T) != 0) typeNames += "<country>|";
+        if ((datatypes & LANGUAGE_T) != 0) typeNames += "<language>|";
+        if ((datatypes & SCRIPT_T) != 0) typeNames += "<script>|";
+        if ((datatypes & URI_SPECIFICATION) != 0) typeNames
+                                                    += "<uri-specification>|";
+        if ((datatypes & TIME) != 0) typeNames += "<time>|";
+        if ((datatypes & FREQUENCY) != 0) typeNames += "<frequency>|";
+        if ((datatypes & BOOL) != 0) typeNames += "<BOOL>|";
+        if ((datatypes & INHERIT) != 0) typeNames += "<INHERIT>|";
+        if ((datatypes & ENUM) != 0) typeNames += "<ENUM>|";
+        if ((datatypes & MAPPED_LENGTH) != 0) typeNames
+                                                    += "<MAPPED_LENGTH>|";
+        if ((datatypes & SHORTHAND) != 0) typeNames += "<SHORTHAND>|";
+        if ((datatypes & COMPLEX) != 0) typeNames += "<COMPLEX>|";
+        if ((datatypes & AUTO) != 0) typeNames += "<AUTO>|";
+        if ((datatypes & NONE) != 0) typeNames += "<NONE>|";
+        if ((datatypes & AURAL) != 0) typeNames += "<AURAL>|";
+        if ((datatypes & COLOR_TRANS) != 0) typeNames += "<COLOR_TRANS>|";
+        if ((datatypes & MIMETYPE) != 0) typeNames += "<MIMETYPE>|";
+        if ((datatypes & FONTSET) != 0) typeNames += "<FONTSET>|";
+
+        if (typeNames == "") throw new PropertyException
+                            ("No valid data type in " + datatypes);
+        return typeNames.substring(0, typeNames.length() - 1);
+    }
+
+    /**
+     * Derive inherited value for the given property.
+     * This method must be overriden by properties with special requirements.
+     * @param foTree the <tt>FOTree</tt> being built
+     * @param property the <tt>int</tt> property index
+     * @return <tt>PropertyValue</tt> the inherited property value for the
+     * property.  It contains the inherited <i>computed</i> value, and no
+     * <i>specified</i> value.
+     * @exception <tt>PropertyException</tt>
+     */
+     /*
+    public static PropertyValue inheritance(FOTree foTree, int property)
+            throws PropertyException
+    {
+        // Is it inherited?  This question is not asked here.  Should it be
+        // determined in here or outside?
+        return foTree.getCurrentInherited(property);
+    }
+    */
+
+    /** Constant for nested <tt>refineParsing</tt> methods. */
+    public static boolean IS_NESTED = true;
+
+    /** Constant for non-nested <tt>refineParsing</tt> methods. */
+    public static boolean NOT_NESTED = false;
+
+    /**
+     * The final stage of property expression parsing.
+     * <ol>
+     *   <li>PropertyTokenizer</li>
+     *   <li>PropertyParser - returns context-free <tt>PropertyValue</tt>s
+     *    recognizable by the parser</li>
+     *   <li>refineParsing - verifies results from parser, translates
+     *    property types like NCName into more specific value types,
+     *    resolves enumeration types, etc.</li>
+     * </ol>
+     *
+     * <p>This method is overriden by individual property classes which
+     * require specific processing.
+     * @param propindex - the <tt>int</tt> property index.
+     * @param foNode - the <tt>FONode</tt> being built
+     * @param value - <tt>PropertyValue</tt> returned by the parser
+     */
+    public PropertyValue refineParsing
+                        (int propindex, FONode foNode, PropertyValue value)
+            throws PropertyException
+    {
+        return refineParsing(propindex, foNode, value, NOT_NESTED);
+    }
+
+    /**
+     * Do the work for the three argument refineParsing method.
+     * @param property - the <tt>int</tt> property index.
+     * @param foNode - the <tt>FONode</tt> being built
+     * @param value - <tt>PropertyValue</tt> returned by the parser
+     * @param nested - <tt>boolean</tt> indicating whether this method is
+     * called normally (false), or as part of another <i>refineParsing</i>
+     * method.
+     * @see #refineParsing(int,FOTree,PropertyValue)
+     */
+    public PropertyValue refineParsing(int property,
+                        FONode foNode, PropertyValue value, boolean nested)
+            throws PropertyException
+    {
+        //int property = value.getProperty();
+        if (property != value.getProperty()) // DEBUG
+            throw new PropertyException
+                ("Mismatched property and value.property.");
+        String propName = PropNames.getPropertyName(property);
+        int proptype = value.getType();
+        int dataTypes = PropertyConsts.pconsts.getDataTypes(property);
+        PropertyValue pv;
+        if ((dataTypes & AURAL) != 0)
+            throw new PropertyNotImplementedException
+                ("AURAL properties are not supported");
+        switch (proptype) {
+        case PropertyValue.NUMERIC:
+            // Can be any of
+            // INTEGER, FLOAT, LENGTH, PERCENTAGE, ANGLE, FREQUENCY or TIME
+            if ((dataTypes & (INTEGER | FLOAT | LENGTH | PERCENTAGE
+                                | ANGLE | FREQUENCY | TIME)) != 0)
+                return value;
+            throw new PropertyException
+                            ("Numeric value invalid  for " + propName);
+        case PropertyValue.INTEGER:
+            if ((dataTypes & NUMBER) != 0)
+                return value;
+            throw new PropertyException
+                    ("IntegerType value invalid for " + propName);
+        case PropertyValue.NCNAME:
+            String ncname = ((NCName)value).getNCName();
+            // Can by any of
+            // NCNAME, COUNTRY_T, LANGUAGE_T, SCRIPT_T, ENUM
+            // MAPPED_LENGTH or CHARACTER_T
+            if ((dataTypes & (NCNAME | CHARACTER_T)) != 0)
+                return value;
+            if ((dataTypes & COUNTRY_T) != 0)
+                return new CountryType(property, ncname);
+            if ((dataTypes & LANGUAGE_T) != 0)
+                return new LanguageType(property, ncname);
+            if ((dataTypes & SCRIPT_T) != 0)
+                return new ScriptType(property, ncname);
+            if ((dataTypes & ENUM) != 0)
+                return new EnumType(property, ncname);
+            if ((dataTypes & MAPPED_LENGTH) != 0)
+                return (new MappedNumeric
+                            (foNode, property, ncname)).getMappedNumValue();
+            throw new PropertyException
+                            ("NCName value invalid  for " + propName);
+        case PropertyValue.ENUM:
+            if ((dataTypes & ENUM) != 0) return value;
+            throw new PropertyException
+                    ( "Enumerated value invalid for " + propName);
+        case PropertyValue.LITERAL:
+            // Can be LITERAL or CHARACTER_T
+            if ((dataTypes & (LITERAL | CHARACTER_T)) != 0) return value;
+            throw new PropertyException
+                            ("Literal value invalid  for " + propName);
+        case PropertyValue.AUTO:
+            if ((dataTypes & AUTO) != 0) return value;
+            throw new PropertyException("'auto' invalid  for " + propName);
+        case PropertyValue.BOOL:
+            if ((dataTypes & BOOL) != 0) return value;
+            throw new PropertyException
+                                ("Boolean value invalid for " + propName);
+        case PropertyValue.COLOR_TYPE:
+            // Can be COLOR_T or COLOR_TRANS
+            if ((dataTypes & (COLOR_T | COLOR_TRANS)) != 0) return value;
+            throw new PropertyException("'none' invalid  for " + propName);
+        case PropertyValue.NONE:
+            // Some instances of 'none' are part of an enumeration, but
+            // the parser will find and return 'none' as a None
+            // PropertyValue.
+            // In these cases, the individual property's refineParsing
+            // method must override this method.
+            if ((dataTypes & NONE) != 0) return value;
+            throw new PropertyException("'none' invalid  for " + propName);
+        case PropertyValue.URI_TYPE:
+            if ((dataTypes & URI_SPECIFICATION) != 0) return value;
+            throw new PropertyException("uri invalid for " + propName);
+        case PropertyValue.MIME_TYPE:
+            if ((dataTypes & MIMETYPE) != 0) return value;
+            throw new PropertyException
+                        ("mimetype invalid for " + propName);
+        // The following types cannot have their values validated in advance.
+        // The result must be validated from within the property type.
+        case PropertyValue.FROM_PARENT:
+            pv = ((FromParent)value).resolve(foNode);
+            if (pv == value) return value;  // unable to resolve
+            // TODO: validate here
+            return pv;
+        case PropertyValue.FROM_NEAREST_SPECIFIED:
+            pv = ((FromNearestSpecified)value).resolve(foNode);
+            if (pv == value) return value;  // unable to resolve
+            // TODO: validate here
+            return pv;
+        case PropertyValue.INHERITED_VALUE:
+            pv = ((InheritedValue)value).resolve(foNode);
+            if (pv == value) return value;  // unable to resolve
+            // TODO: validate here
+            return pv;
+        case PropertyValue.LIST:
+            System.out.println((PropertyValueList)value);
+            throw new PropertyException
+                ("PropertyValueList passed to Property.refineParsing for "
+                + propName);
+        default:
+            if ( ! nested) {
+                if ((dataTypes & COMPOUND) != 0)
+                    return ShorthandPropSets.expandCompoundProperty
+                                            (foNode.getFOTree(), value);
+                if (proptype == PropertyValue.INHERIT) {
+                    if ((dataTypes & INHERIT) != 0)
+                        return ((Inherit)value).resolve(foNode);
+                    throw new PropertyException
+                                    ("'inherit' invalid for " + propName);
+                }
+            }
+            throw new PropertyException
+                ("Inappropriate dataTypes passed to Property.refineParsing: "
+                    + value.getClass().getName());
+        }
+    }
+
+    /**
+     * Refine a list of property values against their properties.
+     * Expansion lists are generated by shorthand and compound expansion.
+     * The set of properties will, in general, be different from the
+     * generating property, which will be the one associated with the list
+     * itself.
+     * @param propindex - the <tt>int</tt> property index.
+     * @param foNode - the <tt>FONode</tt> for which the properties are
+     * being processed.
+     * @param list - the list of <tt>PropertyValues</tt> to be refined.
+     * @return a <tt>PropertyValueList>/tt> containing the refined property
+     * values.
+     */
+    public PropertyValueList refineExpansionList
+                        (int propindex, FONode foNode, PropertyValueList list)
+            throws PropertyException
+    {
+        if (propindex != list.getProperty()) // DEBUG
+            throw new PropertyException
+                ("Mismatch between propindex and list property.");
+        PropertyValueList newlist = new PropertyValueList(list.getProperty());
+        Iterator properties = list.iterator();
+        while (properties.hasNext()) {
+            // refine the next element
+            PropertyValue pv = (PropertyValue)(properties.next());
+            pv = PropertyConsts.pconsts.refineParsing
+                                            (pv.getProperty(), foNode, pv);
+            // if it's a list, recursively refine.  This will return a list
+            if (pv.getType() == PropertyValue.LIST) {
+                PropertyValueList pvl = refineExpansionList
+                        (pv.getProperty(), foNode, (PropertyValueList)pv);
+                newlist.addAll(pvl);
+            } else { // single element
+                newlist.add(pv);
+            }
+        }
+        return newlist;
+    }
+
+    /**
+     * Determine whether argument <i>list</i> contains a space-separated list
+     * from the parser.
+     * A space-separated list will be represented by a
+     * <tt>PropertyValueList</tt> as the only element of the argument
+     * <tt>PropertyValueList</tt>.
+     * @param list - the containing list.
+     * @return the contained space-separated list.
+     * @throws <tt>PropertyException</tt> if <i>list</i> contains more than
+     * one element or if the contained element is not a list.
+     */
+    protected PropertyValueList spaceSeparatedList
+                                                    (PropertyValueList list)
+            throws PropertyException
+    {
+        if (list.size() != 1)
+                throw new PropertyException
+                        (list.getClass().getName() + " list is not a "
+                                + "single list of space-separated values");
+        PropertyValue val2 = (PropertyValue)(list.getFirst());
+        if ( ! (val2.getType() == PropertyValue.LIST))
+                throw new PropertyException
+                        (list.getClass().getName() + " list is not a "
+                                + "single list of space-separated values");
+        return (PropertyValueList)val2;
+    }
+
+    /**
+     * Return the EnumType derived from the argument.
+     * The argument must be an NCName whose string value is a
+     * valid Enum for the property associated with the NCName.
+     * @param value <tt>PropertyValue</tt>
+     * @param property <tt>int</tt> the target property index
+     * @param type <tt>String</tt> type of expected enum - for
+     * exception messages only
+     * @return <tt>EnumValue</tt> equivalent of the argument
+     * @exception <tt>PropertyException</tt>
+     */
+    protected EnumType getEnum(PropertyValue value,
+                                            int property, String type)
+            throws PropertyException
+    {
+        if (value.getType() != PropertyValue.NCNAME)
+            throw new PropertyException
+                (value.getClass().getName()
+                                + " instead of " + type + " for "
+                                + PropNames.getPropertyName(property));
+
+        NCName ncname = (NCName)value;
+        try {
+            return new EnumType(property, ncname.getNCName());
+        } catch (PropertyException e) {
+            throw new PropertyException
+                        (ncname.getNCName()
+                                + " instead of " + type + " for "
+                                + PropNames.getPropertyName(property));
+        }
+    }
+
+    /**
+     * Get the <tt>int</tt> index corresponding to an enumeration keyword
+     * for this property.
+     * @param enum - a <tt>String</tt> containing the enumeration text.
+     * @return <tt>int</tt> constant representing the enumeration value.
+     * @exception PropertyException
+     */
+    public int getEnumIndex(String enum)
+            throws PropertyException
+    {
+        throw new PropertyException("ENUM not supported.");
+    }
+
+    /**
+     * @param enumIndex <tt>int</tt> containing the enumeration index.
+     * @return <tt>String</tt> containing the enumeration text.
+     * @exception PropertyException
+     */
+    public String getEnumText(int enumIndex)
+                    throws PropertyException
+    {
+        throw new PropertyException("ENUM not supported.");
+    }
+
+    /**
+     * Map the String value of an enum to its integer equivalent.
+     * @param value the enum text
+     * @param values an <tt>ROStringArray</tt> of all of the enum text values.
+     * This array is effectively 1-based.
+     * @return the integer equivalent of the enum text
+     * @exception PropertyException if the enum text is not valid.
+     */
+    public int enumValueToIndex(String value, String[] values)
+                throws PropertyException
+    {
+        for (int i = 1; i < values.length; i++) {
+            if (value.equals(values[i])) {
+                return i;
+            }
+        }
+        throw new PropertyException("Enum text " + value +" not found.");
+    }
+
+    /**
+     * Convert an enumeration index value to a length.  This is the
+     * fallback implementation of this function for properties which do not
+     * support a MAPPED_LENGTH type.  Those which do must override this
+     * method.
+     * @param enum - the <tt>int</tt> enumeration index.
+     * @return a <tt>Numeric</tt>.  This implementation never returns.
+     * @throws <tt>PropertyException</tt>.
+     */
+    public Numeric getMappedLength(FONode node, int enum)
+            throws PropertyException
+    {
+        throw new PropertyException
+            ("MAPPED_LENGTH not supported.");
+    }
+
+    /**
+     * Fallback getInitialValue function.  This function only handles
+     * those initial value types NOT in the set USE_GET_IT_FUNCTION.  It
+     * should be overriden by all properties whose initial values come from
+     * that set.
+     * @param property <tt>int</tt> property index
+     * @return <tt>PropertyValue</tt>
+     * @exception <tt>PropertyException</tt>
+     * @exception <tt>PropertyNotImplementedException</tt>
+     */
+    public PropertyValue getInitialValue(int property)
+            throws PropertyException
+    {
+        int initialValueType =
+                    PropertyConsts.pconsts.getInitialValueType(property);
+        //System.out.println("In Property getInitialValue property "
+                            //+ property);
+        if ((initialValueType & Property.USE_GET_IT_FUNCTION) != 0)
+             throw new PropertyException
+                 ("Property.getInitialValue() called for property with "
+                 + "initial value type in USE_GET_IT_FUNCTION : "
+                 + property + " "
+                 + PropNames.getPropertyName(property));
+        switch (initialValueType) {
+        case NOTYPE_IT:
+            return new NoType(property);
+        case AUTO_IT:
+            return new Auto(property);
+        case NONE_IT:
+            return new None(property);
+        case AURAL_IT:
+            throw new PropertyNotImplementedException
+                ("Aural properties not implemented: "
+                + PropNames.getPropertyName(property));
+        default:
+            throw new PropertyException
+                ("Unexpected initial value type " + initialValueType
+                + " for " + PropNames.getPropertyName(property));
+        }
+    }
+
+    /**
+     * 'value' is a PropertyValueList or an individual PropertyValue.
+     * If 'value' is a PropertyValueList, it must contain a single
+     * PropertyValueList, which in turn contains the individual elements.
+     *
+     * 'value' can contain a parsed Inherit value,
+     *  parsed FromParent value, parsed FromNearestSpecified value,
+     *  or, in any order;
+     * border-width
+     *     a parsed NCName value containing a standard border width
+     *     or a Numeric length value (including a percentage)
+     * border-style
+     *     a parsed NCName value containing a standard border style
+     * border-color
+     *     a parsed ColorType value, or an NCName containing one of
+     *     the standard colors
+     *
+     * <p>The value(s) provided, if valid, are converted into a list
+     * containing the expansion of the shorthand.  The elements may
+     * be in any order.  A minimum of one value will be present.
+     *
+     *   a border-EDGE-color ColorType or inheritance value
+     *   a border-EDGE-style EnumType or inheritance value
+     *   a border-EDGE-width MappedNumeric or inheritance value
+     *
+     *  N.B. this is the order of elements defined in
+     *       ShorthandPropSets.borderRightExpansion
+     */
+    protected PropertyValue borderEdge
+                        (int propindex, FONode foNode, PropertyValue value,
+                                int styleProp, int colorProp, int widthProp)
+                throws PropertyException
+    {
+        return borderEdge(propindex, foNode, value, styleProp,
+                                            colorProp, widthProp, NOT_NESTED);
+    }
+
+    protected PropertyValue borderEdge
+            (int propindex, FONode foNode, PropertyValue value, int styleProp,
+                                int colorProp, int widthProp, boolean nested)
+                throws PropertyException
+    {
+        if (value.getType() != PropertyValue.LIST) {
+            return processEdgeValue(propindex, foNode, value,
+                                    styleProp, colorProp, widthProp, nested);
+        } else {
+            return processEdgeList(propindex, foNode,
+                        spaceSeparatedList((PropertyValueList)value),
+                                            styleProp, colorProp, widthProp);
+        }
+    }
+
+    private PropertyValueList processEdgeValue
+            (int propindex, FONode foNode, PropertyValue value, int styleProp,
+                int colorProp, int widthProp, boolean nested)
+            throws PropertyException
+    {
+        if ( ! nested) {
+            int type = value.getType();
+            if (type == PropertyValue.INHERIT ||
+                    type == PropertyValue.FROM_PARENT ||
+                        type == PropertyValue.FROM_NEAREST_SPECIFIED)
+            {
+                // Copy the value to each member of the shorthand expansion
+                return refineExpansionList(propindex, foNode,
+                                ShorthandPropSets.expandAndCopySHand(value));
+            }
+        }
+        // Make a list and pass to processList
+        PropertyValueList tmpList = new PropertyValueList(propindex);
+        tmpList.add(value);
+        return processEdgeList
+                (propindex, foNode, tmpList, styleProp, colorProp, widthProp);
+    }
+
+    private PropertyValueList processEdgeList
+            (int property, FONode foNode, PropertyValueList value,
+                                int styleProp, int colorProp, int widthProp)
+                    throws PropertyException
+    {
+        //int property = value.getProperty();
+        String propName = PropNames.getPropertyName(property);
+        PropertyValue   color= null,
+                        style = null,
+                        width = null;
+
+        PropertyValueList newlist = new PropertyValueList(property);
+        // This is a list
+        if (value.size() == 0)
+            throw new PropertyException
+                            ("Empty list for " + propName);
+        Iterator elements = ((PropertyValueList)value).iterator();
+
+        scanning_elements: while (elements.hasNext()) {
+            PropertyValue pval = (PropertyValue)(elements.next());
+            int type = pval.getType();
+            switch (type) {
+            case PropertyValue.COLOR_TYPE:
+                if (color != null) MessageHandler.logln(propName +
+                            ": duplicate color overrides previous color");
+                color = pval;
+                color.setProperty(colorProp);
+                continue scanning_elements;
+            case PropertyValue.NUMERIC:
+                if (width != null) MessageHandler.logln(propName +
+                            ": duplicate width overrides previous width");
+                width = pval;
+                width.setProperty(widthProp);
+                continue scanning_elements;
+            case PropertyValue.NCNAME:
+                // Could be standard color, style Enum or width MappedNumeric
+                PropertyValue colorFound = null;
+                PropertyValue styleFound = null;
+                PropertyValue widthFound = null;
+
+                String ncname = ((NCName)pval).getNCName();
+                try {
+                    styleFound = new EnumType(styleProp, ncname);
+                } catch (PropertyException e) {}
+                if (styleFound != null) {
+                    if (style != null) MessageHandler.logln(propName +
+                            ": duplicate style overrides previous style");
+                    style = styleFound;
+                    continue scanning_elements;
+                }
+
+                try {
+                    widthFound =
+                        (new MappedNumeric
+                            (foNode, widthProp, ncname)).getMappedNumValue();
+                } catch (PropertyException e) {}
+                if (widthFound != null) {
+                    if (width != null) MessageHandler.logln(propName +
+                            ": duplicate width overrides previous width");
+                    width = widthFound;
+                    continue scanning_elements;
+                }
+
+                try {
+                    colorFound = new ColorType(colorProp, ncname);
+                } catch (PropertyException e) {};
+                if (colorFound != null) {
+                    if (color != null) MessageHandler.logln(propName +
+                            ": duplicate color overrides previous color");
+                    color = colorFound;
+                    continue scanning_elements;
+                }
+
+                throw new PropertyException
+                    ("Unknown NCName value for " + propName + ": " + ncname);
+            default:
+                throw new PropertyException
+                    ("Invalid " + pval.getClass().getName() +
+                        " property value for " + propName);
+            } // end of switch
+        }
+
+        // Now construct the list of PropertyValues with their
+        // associated property indices, as expanded from the
+        // border-right shorthand.
+        if (style != null) newlist.add(style);
+        if (color != null) newlist.add(color);
+        if (width != null) newlist.add(width);
+        return newlist;
+    }
+
+}
+
+ +