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;
public class Property {
private static final String tag = "$Name$";
private static final String revision = "$Revision$";
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
,BOOL = 32768
,INHERIT = 65536
,ENUM = 131072
,MAPPED_LENGTH = 262144
,SHORTHAND = 524288
,COMPLEX = 1048576
,AUTO = 2097152
,NONE = 4194304
,AURAL = 8388608
,COLOR_TRANS = 16777216
,MIMETYPE = 33554432
,FONTSET = 67108864
,COMPOUND = 134217728
,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
;
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
;
public static final int
USE_GET_IT_FUNCTION = 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
| TEXT_DECORATION_IT
;
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
;
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() {}
@paramdatatypes@return@exceptionPropertyException
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);
}
@paramfoTree@paramproperty@returncomputedspecified@exception<tt>PropertyException</tt>
public static boolean IS_NESTED = true;
public static boolean NOT_NESTED = false;
@parampropindex@paramfoNode@paramvalue
public PropertyValue refineParsing
(int propindex, FONode foNode, PropertyValue value)
throws PropertyException
{
return refineParsing(propindex, foNode, value, NOT_NESTED);
}
@paramproperty@paramfoNode@paramvalue@paramnestedrefineParsing@see#refineParsing
public PropertyValue refineParsing(int property,
FONode foNode, PropertyValue value, boolean nested)
throws PropertyException
{
if (property != value.getProperty()) 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:
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();
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:
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:
if ((dataTypes & (COLOR_T | COLOR_TRANS)) != 0) return value;
throw new PropertyException("'none' invalid for " + propName);
case PropertyValue.NONE:
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);
case PropertyValue.FROM_PARENT:
pv = ((FromParent)value).resolve(foNode);
if (pv == value) return value; return pv;
case PropertyValue.FROM_NEAREST_SPECIFIED:
pv = ((FromNearestSpecified)value).resolve(foNode);
if (pv == value) return value; return pv;
case PropertyValue.INHERITED_VALUE:
pv = ((InheritedValue)value).resolve(foNode);
if (pv == value) return value; 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());
}
}
@parampropindex@paramfoNode@paramlist@return
public PropertyValueList refineExpansionList
(int propindex, FONode foNode, PropertyValueList list)
throws PropertyException
{
if (propindex != list.getProperty()) throw new PropertyException
("Mismatch between propindex and list property.");
PropertyValueList newlist = new PropertyValueList(list.getProperty());
Iterator properties = list.iterator();
while (properties.hasNext()) {
PropertyValue pv = (PropertyValue)(properties.next());
pv = PropertyConsts.pconsts.refineParsing
(pv.getProperty(), foNode, pv);
if (pv.getType() == PropertyValue.LIST) {
PropertyValueList pvl = refineExpansionList
(pv.getProperty(), foNode, (PropertyValueList)pv);
newlist.addAll(pvl);
} else { newlist.add(pv);
}
}
return newlist;
}
list@paramlist@return@throws<tt>PropertyException</tt>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;
}
@paramvalue@paramproperty@paramtype@return@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));
}
}
@paramenum@return@exceptionPropertyException
public int getEnumIndex(String enum)
throws PropertyException
{
throw new PropertyException("ENUM not supported.");
}
@paramenumIndex@return@exceptionPropertyException
public String getEnumText(int enumIndex)
throws PropertyException
{
throw new PropertyException("ENUM not supported.");
}
@paramvalue@paramvalues@return@exceptionPropertyException
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.");
}
@paramenum@return@throws<tt>PropertyException</tt>.
public Numeric getMappedLength(FONode node, int enum)
throws PropertyException
{
throw new PropertyException
("MAPPED_LENGTH not supported.");
}
@paramproperty@return@exception<tt>PropertyException</tt>
@exception<tt>PropertyNotImplementedException</tt>
public PropertyValue getInitialValue(int property)
throws PropertyException
{
int initialValueType =
PropertyConsts.pconsts.getInitialValueType(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));
}
}
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)
{
return refineExpansionList(propindex, foNode,
ShorthandPropSets.expandAndCopySHand(value));
}
}
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
{
String propName = PropNames.getPropertyName(property);
PropertyValue color= null,
style = null,
width = null;
PropertyValueList newlist = new PropertyValueList(property);
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:
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);
} }
if (style != null) newlist.add(style);
if (color != null) newlist.add(color);
if (width != null) newlist.add(width);
return newlist;
}
}