Property Handling

General Info

FOP's property subsystem is a component that is easily misunderstood. and its derived classes do not exactly correspond to FO properties, but rather, different types of FO properties. The mapping of a FO property name to a Property subclass is defined in, a class that seems a bit intimidating at first glance...


While the source file seems immense, all the code in there is only executed once for multiple FOP runs within the same virtual machine. What it gets to contain after this code has been executed, is a mapping of FO property names to one of the subclasses. Those PropertyMakers have been customized to fit the behavior as mandated by or prescribed in the XSL-FO Recommendation for a given property, such as:

The customized PropertyMakers in FOPropertyMapping are used when the tree of FOs is built from the XML events coming in from the SAX Parser. In the current node's list of attributes is given to an instance of, which uses the attribute names and FOPropertyMapping to get to the right PropertyMakers to convert each of the attribute values to the appropriate FOP-internal Property type.

The PropertyMakers

There are two distinct points in the overall process where PropertyMakers are used:

Conversion of explicitly specified FO properties

This is initiated in PropertyList.convertAttributeToProperty(), and in the most basic case comes down to a call to PropertyMaker.make(PropertyList,String,FObj). The default implementation of this method provides for the following:

  1. resolving explicit inheritance (specified value of "inherit")

  2. substitution of value keywords (checkValueKeywords())

  3. checking valid enum values (checkEnumValues())

  4. parsing the expression (PropertyParser.parse()), if the above did not yet yield a Property

  5. converting the resulting Property, if any, to the right type (convertProperty())

This method can be overridden by subclasses, for example to cater for custom property parsing if the generic does not suffice (see, which bypasses the generic space-based expression parsing).

Binding a FOP PropertyList to an FObj

This is done in, and results in an FObj being tied to the set of applicable properties, so that the PropertyList (which reserves space for all possible properties) is no longer needed. In case of the explicitly specified properties, the PropertyMaker's role here is limited to finding the Property on the PropertyList and simply returning it unaltered. What the PropertyMakers are mostly used for in this part of the process is:

What about those PropertyLists?

PropertyLists are large, but relatively short-lived in most cases. The PropertyList for the first fo:block in an fo:flow is released before the one for its sibling fo:block is created; only a reference to the parent is maintained (see FOTreeBuilder.MainFOHandler.endElement(): the currentPropertyList is set back to that of the parent FO, so the one for the processed node goes out of scope). The only notable exception is the PropertyList-ancestry of fo:retrieve-markers: that is preserved until layout, to be able to correctly deal with markers and property inheritance. The MarkerPropertyList subclass used for the attributes of descendants of an fo:marker themselves is actually a hybrid of PropertyList and SAX Attributes. It only stores simple name-value mappings and implements the Attributes interface so it can itself be used to create a full-fledged StaticPropertyList later on, when the marker is retrieved. (Note that a simple reference to the original Attributes does not suffice here, since the SAX parser is under no obligation to keep it available after the parent element's endElement() has passed, which is long before the point where they would be needed.)

PropertyLists are primarily important for:

  1. resolving inheritance
  2. triggering shorthand expansion
  3. computing properties from corresponding properties

They are designed to be a bridge between the FObjs and the PropertyMakers. The PropertyList is constructed separately from the FO, and first filled with the explicitly specified properties. In the bind() method, each subclass issues get(PR_XX)-requests for all applicable (and implemented) properties to the PropertyList, which in turn can trigger additional PropertyMakers' get()-calls.

Property Inheritance

Inheritance is handled almost entirely by the PropertyList, and comes down to having the PropertyMaker check whether the property is inherited, and if so, have it forward the get(PR_XX)-call to the parentPropertyList.

Shorthand Expansion

If there is no explicitly specified value available and the PropertyMaker was customized to allow the property to be set by a shorthand, the request is forwarded via the shorthand's PropertyMaker to the defined ShorthandParser implementation. As long as the FO has not requested the base properties, the shorthand is stored as a single Property instance whose associated PropertyMaker instance contains a ShorthandParser that is designed to serve get(PR_XX)-requests for the base properties. Once the bind() method has been executed, most of the shorthands themselves will only be referenced by (and thus, later on disappear together with) the PropertyList.

Example: resolution of a specified shorthand property

FO Source:

<fo:block white-space="pre">...

Conversion of the explicitly specified shorthand:

in PropertyList.convertAttributeToProperty():
 propertyMaker = findMaker(PR_WHITE_SPACE);
 --> propertyMaker is an EnumProperty.Maker, equipped with a custom WhiteSpaceShorthandParser (see FOPropertyMapping.createShorthandProperties())
 property = propertyMaker.make(this, "pre", parentFO);
 --> property is the EnumProperty(EN_PRE, "PRE")

Expansion of the explicitly specified shorthand:

in Block.bind():
 linefeedTreatment = pList.get(PR_LINEFEED_TREATMENT).getEnum();

in PropertyList.get():
 propertyMaker = findMaker(PR_LINEFEED_TREATMENT);
 --> propertyMaker is an EnumProperty.Maker, that was customized to be possibly set by the PR_WHITE_SPACE shorthand (see FOPropertyMapping.createBlockAndLineProperties())
 property = propertyMaker.get(0, propertyList, true, true);

in PropertyMaker.get():
 property = findProperty(propertyList, true);
in PropertyMaker.findProperty():
 property = getShorthand(propertyList);

in PropertyMaker.getShorthand():
 prop = propertyList.getExplicit(PR_WHITE_SPACE);
 parser = shorthand.datatypeParser
 --> parser is a WhiteSpaceShorthandParser
 property = parser.getValueForProperty(PR_LINEFEED_TREATMENT, prop, this, propertyList);

in WhiteSpaceShorthandParser.getValueForProperty():
 return EnumProperty.getInstance(EN_PRESERVE, "PRESERVE");

Corresponding Property Computation

This is performed analogously, by involving another PropertyMaker that was associated to the base property's Maker in FOPropertyMapping.

Implementing an additional FO property in FOP without implementing a Property?

It's possible, if the property's datatype is already supported, which will be the case for most types of property, like NumberProperty, StringProperty or EnumProperty.


see PropertyHandling/Percentages

PropertyHandling (last edited 2009-09-20 23:52:33 by localhost)