1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
|
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.3//EN" "http://forrest.apache.org/dtd/document-v13.dtd">
<document>
<header>
<title>FOP Design: Properties</title>
<version>$Revision$</version>
<authors>
<person name="Karen Lease" email=""/>
</authors>
</header>
<body>
<section id="intro">
<title>Introduction</title>
<p>As the input XSL-FO is being parsed and the FO Tree is being built, the attributes of the FO elements are passed by the parser to the related FO object.
The java object that represent the FO object then converts the attributes into properties that are stored in the FO Tree.</p>
</section>
<section id="issues">
<title>Issues</title>
<p>The following are some issues when dealing with properties:</p>
<ul>
<li>Initial Property Set</li>
<li>Inheritance: Some properties can be inherited from parent objects.</li>
<li>Adoption: The parentage for some elements can move around.
Markers are one example.</li>
<li>Multiple Namespaces: The properties for foreign namespaces must be handled.</li>
<li>Expressions: XSL-FO expressions can be included in properties.</li>
</ul>
</section>
<section id="process-overview">
<title>Overview of Processing</title>
<p>The general flow of property processing is as follows:</p>
<ul>
<li>As part of <code>FOTreeBuilder.startElement()</code>, <code>FObj.handleAttrs</code> is passed a list of attributes to be processed for the new FObj.</li>
<li>FObj.handleAttrs gets a PropertyListBuilder and asks it to create a Property List from the list of attributes. There is currently only one static PropertyListBuilder, which handles the fo: namespace.</li>
<li>FObj.handleAttrs then cross-references the returned PropertyList with the FObj, creates a PropertyManager to facilitate downstream processing of the PropertyList, and handles the special case of the writing-mode property.</li>
</ul>
</section>
<section id="plb">
<title>PropertyListBuilder</title>
<p>Each plb object contains a hash of
property names and <em>their</em> respective Makers. It may also
contain element-specific property maker hashes; these are based on the
<em>local name</em> of the flow object, ie. <em>table-row</em>, not
<em>fo:table-row</em>. If an element-specific property mapping exists,
it is preferred to the generic mapping.</p>
<p>The PLB loops through each attribute in the list, finds an appropriate "Maker" for it, then calls the Maker to convert the attribute value into a Property object of the correct type, and stores that Property in the PropertyList.</p>
</section>
<section id="datatypes">
<title>Property datatypes</title>
<p>The property datatypes are defined in the
org.apache.fop.datatypes package, except Number and String which are java
primitives. The FOP datatypes are:</p>
<ul>
<li>Number</li>
<li>String</li>
<li>ColorType</li>
<li>Length (has several subclasses)</li>
<li>CondLength (compound)</li>
<li>LengthRange (compound)</li>
<li>Space (compound)</li>
<li>Keep (compound)</li>
</ul>
<p>The <em>org.apache.fop.fo.Property</em> class is the superclass for all
Property subclasses. There is a subclass for each kind of property
datatype. These are named using the datatype name plus the word
Property, resulting in NumberProperty, StringProperty, and so
on. There is also a class EnumProperty which uses an <code>int</code>
primitive to hold enumerated values. There is no corresponding Enum
datatype class.</p>
<p>The Property class provides a "wrapper" around any possible
property value. Code manipulating property values (in layout for
example) usually knows what kind (or kinds) of datatypes are
acceptable for a given property and will use the appropriate accessor.</p>
<p>The base Property class defines accessor methods for all FO property
datatypes, such as getNumber(), getColorType(), getSpace(), getEnum(),
etc. It doesn't define
accessors for SVG types, since these are handled separately (at least
for now.) In the base Property class, all of these methods return
null, except getEnum which returns 0. Individual subclasses return a value of the appropriate type,
such as Length or ColorType. A subclass may also choose to return a
reasonable value for other accessor types. For example, a
SpaceProperty will return the optimum value if asked for a Length.</p>
</section>
<section id="makers">
<title>Property Makers</title>
<p>The Property class contains a nested class called
<em>Maker</em>. This is the base class for all other property Makers. It
provides basic framework functionality which is overridden by the
code generated by properties.xsl from the *properties.xml files. In
particular it provides basic expression evaluation, using
PropertyParser class in the org.apache.fop.fo.expr package.</p>
<p>Other Property subclasses such as LengthProperty define their own
nested Maker classes (subclasses of Property.Maker). These handle
conversion from the Property subclass returned from expression
evaluation into the appropriate subclass for the property.</p>
<p>For each generic or specific property definition in the
properties.xml files, a new subclass of one of the Maker classes is
created. Note that no new Property subclasses are created, only new
PropertyMaker subclasses. Once the property value has been parsed and
stored, it has no specific functionality. Only the Maker code is
specific. Maker subclasses define such aspects as keyword
substitutions, whether the property can be inherited or not, which
enumerated values are legal, default values, corresponding properties
and specific datatype conversions.</p>
<p>The PLB finds a "Maker" for the property based on the attribute name and
the element name. Most Makers are generic and handle the attribute on
any element, but it's possible to set up an element-specific property
Maker. The attribute name to Maker mappings are automatically created
during the code generation phase by processing the XML property
description files.</p>
</section>
<section id="attribute-list">
<title>Processing the attribute list</title>
<p>The PLB first looks to see if the font-size property is specified, since
it sets up relative units which can be used in other property
specifications. Each attribute is then handled in turn. If the attribute
specifies part of a compound property such as space-before.optimum, the
PLB looks to see if the attribute list also contains the "base" property
(space-before in this case) and processes that first.</p>
</section>
<section id="maker-design">
<title>How the Property Maker works</title>
<p>There is a family of Maker objects for each of the property datatypes,
such as Length, Number, Enumerated, Space, etc. But since each Property
has specific aspects such as whether it's inherited, its default value,
its corresponding properties, etc. there is usually a specific Maker for
each Property. All these Maker classes are created during the code
generation phase by processing (using XSLT) the XML property description
files to create Java classes.</p>
<p>The Maker first checks for "keyword" values for a property. These are
things like "thin, medium, thick" for the border-width property. The
datatype is really a Length but it can be specified using these keywords
whose actual value is determined by the "User Agent" rather than being
specified in the XSL standard. For FOP, these values are currently
defined in foproperties.xml. The keyword value is just a string, so it
still needs to be parsed as described next.</p>
<p>The Maker also checks to see if the property is an Enumerated type and
then checks whether the value matches one of the specified enumeration
values.</p>
<p>Otherwise the Maker uses the property parser in the fo.expr package to
evaluate the attribute value and return a Property object. The parser
interprets the expression language and performs numeric operations and
function call evaluations.</p>
<p>If the returned Property value is of the correct type (specificed in
foproperties.xml, where else?), the Maker returns it. Otherwise, it may
be able to convert the returned type into the correct type.</p>
<p>Some kinds of property values can't be fully resolved during FO tree
building because they depend on layout information. This is the case of
length values specified as percentages and of the special
proportional-column-width(x) specification for table-column widths.
These are stored as special kinds of Length objects which are evaluated
during layout. Expressions involving "em" units which are relative to
font-size _are_ resolved during the FO tree building however.</p>
</section>
<section id="property-list-struct">
<title>Structure of the PropertyList</title>
<p>The PropertyList extends HashMap and its basic function is to associate
Property value objects with Property names. The Property objects are all
subclasses of the base Property class. Each one simply contains a
reference to one of the property datatype objects. Property provides
accessors for all known datatypes and various subclasses override the
accessor(s) which are reasonable for the datatype they store.</p>
<p>The PropertyList itself provides various ways of looking up Property
values to handle such issues as inheritance and corresponding
properties.</p>
<p>The main logic is:<br/>If the property is a writing-mode relative property (using start, end,
before or after in its name), the corresponding absolute property value
is returned if it's explicitly set on this FO. <br/>Otherwise, the
writing-mode relative value is returned if it's explicitly set. If the
property is inherited, the process repeats using the PropertyList of the
FO's parent object. (This is easy because each PropertyList points to
the PropertyList of the nearest ancestor FO.) If the property isn't
inherited or no value is found at any level, the initial value is
returned.</p>
</section>
<section id="property-spec">
<title>Implementing Standard Properties</title>
<p>Because the properties defined in the standard are basically static, FOP currently builds the source code for the related Property classes from an XML data file.
All properties are specified in src/codegen/foproperties.xml.
The related classes are created automatically during the build process by applying an XSLT stylesheet to the foproperties.xml file.</p>
<section id="generic">
<title>Generic properties</title>
<p>In the properties xml files, one can define generic property
definitions which can serve as a basis for individual property
definitions. There are currently several generic properties defined in
foproperties.xml. An example is GenericColor, which defines basic properties
for all ColorType properties. Since the generic specification doesn't include
the inherited or default elements, these should be set in each property
which is based on GenericColor. Here is an example:</p>
<p>
<code><property type='generic'>
<name>background-color</name>
<use-generic>GenericColor</use-generic>
<inherited>false</inherited>
<default>transparent</default>
</property></code>
</p>
<p>A generic property specification can include all of the elements
defined for the property element in the DTD, including the description
of components for compound properties, and the specification of
keyword shorthands.</p>
<p>Generic property specifications can be based on other generic
specifications.
An example is GenericCondPadding template which is based on the
GenericCondLength definition but which extends it by adding an inherited
element and a default value for the length component.</p>
<p>Generic properties can specify enumerated values, as in the
GenericBorderStyle template. This means that the list of values, which
is used by 8 properties (the "absolute" and "writing-mode-relative"
variants for each BorderStyle property) is only specified one time.</p>
<p>When a property includes a "use-generic" element and includes no other
elements (except the "name" element), then no class is generated for the
property. Instead the generated mapping will associate this
property directly with an instance of the generic Maker.</p>
<p>A generic class may also be hand-coded, rather than generated from the
properties file.
Properties based on such a generic class are indicated by the
attribute <code>ispropclass='true'</code> on the
<em>use-generic</em> element.</p>
<p>This is illustrated by the SVG properties, most of
which use one of the Property subclasses defined in the
<em>org.apache.fop.svg</em>
package. Although all of these properties are now declared in
svgproperties.xml, no specific classes are generated. Classes are only
generated for those SVG properties which are not based on generic
classes defined in svg.</p>
</section>
<section id="element-specific">
<title>Element-specific properties</title>
<p>Properties may be defined for all flow objects or only for
particular flow objects. A PropertyListBuilder object will always look
first for a Property.Maker for the flow object before looking in the
general list. These are specified in the
<code>element-property-list</code> section of the properties.xml
files. The <code>localname</code> element children of this element specify for
which flow-object elements the property should be registered.</p>
<p>
<em>NOTE</em>: All the properties for an object or set of objects
must be specified in a single element-property-list element. If the
same localname appears in several element lists, the later set of
properties will hide the earlier ones! Use the <em>ref</em>
functionality if the same property is to be used in different sets of
element-specific mappings.</p>
</section>
<section id="reference">
<title>Reference properties</title>
<p>A property element may have a type attribute with the value
<code>ref</code>. The
content of the <em>name</em> child element is the name of the referenced
property (not its class-name!). This indicates that the property
specification has
already been given, either in this same specification file or in a
different one (indicated by the <code>family</code> attribute). The
value of the family attribute is <em>XX</em> where the file
<em>XXproperties.xml</em> defines the referenced property. For
example, some SVG objects may have properties defined for FO. Rather
than defining them again with a new name, the SVG properties simply
reference the defined FO properties. The generating mapping for the
SVG properties will use the FO Maker classes.</p>
</section>
<section id="corresponding">
<title>Corresponding properties</title>
<p>Some properties have both <em>absolute</em> and
<em>writing-mode-relative</em> forms. In general, the absolute forms
are equivalent to CSS properties, and the writing-mode-relative forms
are based on DSSSL. FO files may use either or both forms. In
FOP code, a request for an absolute form will retrieve that value if it
was specified on the FO; otherwise the corresponding relative property
will be used if it was specified. However, a request for a relative
form will only use the specified relative value if the corresponding
absolute value was <em>not</em> specified for that FO.</p>
<p>Corresponding properties are specified in the properties.xml files
using the element <code>corresponding</code>, which has at least one
<code>propval</code> child and may have a <code>propexpr</code> child,
if the corresponding
value is calculated based on several other properties, as for
<code>start-indent</code>.</p>
<p>
<em>NOTE</em>: most current FOP code accesses the absolute variants
of these properties, notably for padding, border, height and width
attributes. However it does use start-indent and end-indent, rather
than the "absolute" margin properties.</p>
</section>
</section>
<section id="mapping">
<title>Mapping</title>
<p>The XSL script <code>propmap.xsl</code> is used to generate
property mappings based on
both foproperties.xml and svgproperties.xml. The mapping classes
in the main fop packages simply load these automatically generated
mappings. The mapping code still uses the static
"maker" function of the generated object to obtain a Maker
object. However, for all generated classes, this method returns an
instance of the class itself (which is a subclass of Property.Maker)
and not an instance of a separate nested Maker class.</p>
<p>For most SVG properties which use the SVG Property classes directly,
the generated mapper code calls the "maker" method of the SVG Property
class, which returns an instance of its nested Maker class.</p>
<p>The property generation also handles element-specific property
mappings as specified in the properties XML files.</p>
</section>
<section id="enumerated">
<title>Enumerated values</title>
<p>For any property whose datatype is <code>Enum</code> or which
contains possible enumerated values, FOP code may need to access
enumeration constants. These are defined in the interfaces whose name
is the same as the generated class name for the property,
for example <code>BorderBeforeStyle.NONE</code>. These interface classes
are generated by the XSL script <code>enumgen.xsl</code>. A separate
interface defining the enumeration constants is always generated for
every property which uses the constants, even if the constants
themselves are defined in a generic class, as in BorderStyle.</p>
<p>If a subproperty or component of a compound property has enumerated
values, the constants are defined in a nested interface whose name is
the name of the subproperty (using appropriate capitalization
rules). For example,
the keep properties may have values of AUTO or FORCE or an integer
value. These are defined for each kind of keep property. For example,
the keep-together property is a compound property with the components
within-line, within-column and within-page. Since each component may
have the values AUTO or FORCE, the KeepTogether interface defines
three nested interfaces, one for each component, and each defines
these two constants. An example of a reference in code to the constant
is <code>KeepTogether.WithinPage.AUTO</code>.</p>
</section>
<section id="compound">
<title>Compound property types</title>
<p>Some XSL FO properties are specified by compound datatypes. In the FO file,
these are defined by a group of attributes, each having a name of the
form <code>property.component</code>, for example
<code>space-before.minimum</code>. These are several compound
datatypes:</p>
<ul>
<li>LengthConditional, with components length and conditionality</li>
<li>LengthRange, with components minimum, optimum, and maximum</li>
<li>Space, with components minimum, optimum, maximum, precedence and
conditionality </li>
<li>Keep, with components within-line, within-column and within-page</li>
</ul>
<p>These are described in the properties.xml files using the element
<code>compound</code> which has <code>subproperty</code> children. A subproperty element is much
like a property element, although it may not have an <code>inherited</code> child
element, as only a complete property object may be inherited.</p>
<p>Specific datatype classes exist for each compound property. Each
component of a compound datatype is itself stored as a Property
object. Individual components may be accessed either by directly
performing a get operation on the name, using the "dot" notation,
eg. <code>get("space-before.optimum")</code>; or by using an accessor on the compound
property, eg. <code>get("space-before").getOptimum()</code>.
In either case,
the result is a Property object, and the actual value may be accessed
(in this example) by using the "getLength()" accessor.</p>
</section>
<section id="refine">
<title>Refinement</title>
<p>The <strong>Refinement</strong> step is part of reading and using the properties which may happen immediately or during the layout process. FOP does not currently use a separate Refinement process, but tends to handle refining steps as the FO Tree is built.</p>
</section>
<section id="refined-fo-tree">
<title>Refined FO Tree</title>
<p>The Refined FO Tree is the result of the Refinement process.</p>
</section>
</body>
</document>
|