| <?xml version="1.0" encoding="utf-8"?> |
| |
| <!-- |
| * 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 chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" |
| "docbookx.dtd"> |
| --> |
| |
| <chapter id="ch.properties"> |
| <title>Properties</title> |
| |
| <section> |
| <title>The basic setup of the property subsystem</title> |
| |
| <section> |
| <title>Property values</title> |
| |
| <para>The FO nodes in the FO tree contain property values as specified |
| by the user. Each property value is represented by a object of type |
| <literal>org.apache.fop.fo.Property</literal>, or of a subtype |
| thereof.</para> |
| |
| <para>There are various types of property values: |
| <literal>CharacterProperty</literal>, |
| <literal>ColorTypeProperty</literal>, |
| <literal>CondLengthProperty</literal>, |
| <literal>EnumProperty</literal>, <literal>KeepProperty</literal>, |
| <literal>LengthPairProperty</literal>, |
| <literal>LengthProperty</literal>, |
| <literal>LengthRangeProperty</literal>, |
| <literal>ListProperty</literal>, <literal>NCnameProperty</literal>, |
| <literal>NumberProperty</literal>, <literal>NumericProperty</literal>, |
| <literal>RelativeNumericProperty</literal>, |
| <literal>StringProperty</literal>. The type |
| <literal>ToBeImplementedProperty</literal> is used for properties that |
| are not yet implemented. Some of these types have subtypes: |
| <literal>AutoLength</literal>, <literal>FixedLength</literal>, |
| <literal>PercentLength</literal>, <literal>TableColLength</literal> |
| are subclasses of <literal>LengthProperty</literal>; |
| <literal>SpaceProperty</literal> is a subclass of |
| <literal>LengthRangeProperty</literal>. Each of these types is a |
| subtype of <literal>org.apache.fop.fo.Property</literal>. |
| </para> |
| |
| <para>Property values may implement one or more of the interfaces |
| defined in the package <literal>org.apache.fop.datatypes</literal>: |
| <literal>Numeric</literal>, <literal>Length</literal>, |
| <literal>ColorType</literal></para> |
| |
| <para>Some properties actually represent a set of properties, such |
| as a minimum, an optimum and a maximum. These are represented by a |
| property value which implements the |
| <literal>CompoundDatatype</literal> interface. They contain a property |
| value for each member property.</para> |
| |
| </section> |
| |
| <section> |
| <title>The property list of an FO node</title> |
| |
| <para>Property values are held by the FO node corresponding to |
| the fo element on which they are specified by the user. FO nodes |
| contain a property list of type <literal>PropertyList</literal>, which |
| extends <literal>HashMap</literal>.</para> |
| |
| <para>The property types are known by the property |
| name as used on the FO element, e.g. <literal>font-size</literal>. For |
| efficiency of implementation, each type of property type is also known by |
| an <literal>integer</literal>, the <literal>propID</literal>. The |
| <literal>propID</literal>s are defined in the interface |
| <literal>org.apache.fop.fo.Constants</literal>, which gives them a |
| symbolic name of the form <literal>PR_</literal> + property name in |
| capitals and spaces replaced by underscores, |
| e.g. <literal>PR_FONT_SIZE</literal>. Wherever possible, the code uses |
| the <literal>propID</literal>s instead of the property names.</para> |
| |
| <para>When an FO requests a property, it does so by |
| <literal>propId</literal>. The request is eventually answered by |
| <literal>PropertyList.getExplicitBaseProp</literal>, but before it can |
| do so, it has to retrieve the property name from |
| <literal>FOPropertyMapping.getPropertyName</literal>. A particular |
| inefficiency as a consequence is found in |
| <filename>FopPropValFunction.java</filename> and some other classes in |
| the <literal>fo.expr</literal> package: |
| |
| <screen> |
| return pInfo.getPropertyList().get(FOPropertyMapping.getPropertyId(propName)) |
| </screen> |
| |
| Here <literal>propName</literal> -> <literal>propId</literal> mapping |
| is done, which later is reverted again.</para> |
| |
| <screen> |
| [1] org.apache.fop.fo.FOPropertyMapping.getPropertyName (FOPropertyMapping.java:486) |
| [2] org.apache.fop.fo.PropertyList.getExplicitBaseProp (PropertyList.java:230) |
| [3] org.apache.fop.fo.Property$Maker.findProperty (Property.java:281) |
| [4] org.apache.fop.fo.Property$Maker.get (Property.java:314) |
| [5] org.apache.fop.fo.PropertyList.get (PropertyList.java:281) |
| [6] org.apache.fop.fo.PropertyList.get (PropertyList.java:267) |
| [7] org.apache.fop.fo.FObj.getProperty (FObj.java:261) |
| </screen> |
| |
| </section> |
| |
| <section> |
| <title>Property makers</title> |
| |
| <para>Property value objects are created by a property maker of |
| type <literal>org.apache.fop.fo.PropertyMaker</literal>, or of a |
| subtype thereof. For each property type there is a property maker |
| object, which knows the property type, its default value, and some |
| other characteristics.</para> |
| |
| <para>The types of property makers are: |
| <literal>CharacterProperty.Maker</literal>, |
| <literal>ColorTypeProperty.Maker</literal>, |
| <literal>CompoundPropertyMaker</literal>, |
| <literal>EnumProperty.Maker</literal>, |
| <literal>LengthProperty.Maker</literal>, |
| <literal>ListProperty.Maker</literal>, |
| <literal>NumberProperty.Maker</literal>, |
| <literal>StringProperty.Maker</literal>, and |
| <literal>ToBeImplementedProperty.Maker</literal>.</para> |
| |
| <para>The property makers are lazily constructed when the |
| <literal>FObj</literal> constructor wants to create its static member |
| <literal>propertyListTable</literal>. The constructor calls |
| <literal>FOPropertyMapping.getGenericMappings()</literal>, which |
| constructs and returns |
| <literal>Property.Maker[Constants.PROPERTY_COUNT+1] |
| s_generics</literal>. The FObj constructor then copies this array of |
| <literal>PropertyMaker</literal>s into |
| <literal>propertyListTable</literal>.</para> |
| |
| <para><literal>public static PropertyMaker[] |
| getGenericMappings()</literal> first creates the shorthand property |
| makers, so that they can be used in the creation of the makers of the |
| real properties, and a set of generic property makers, which act as |
| templates for the real property makers. Next it creates the makers for |
| all property types. Related property types are grouped, |
| e.g. <literal>createFontProperties()</literal>.</para> |
| |
| <para>An example is the creation of the maker for the |
| <literal>font-size</literal> property type: |
| |
| <screen> |
| m = new LengthProperty.Maker(PR_FONT_SIZE); |
| m.setInherited(true); |
| m.setDefault("12pt"); |
| m.setPercentBase(LengthBase.INH_FONTSIZE); |
| addPropertyMaker("font-size", m); |
| </screen> |
| |
| Since <literal>font-size</literal> is a length, its maker is a |
| <literal>LengthProperty.Maker</literal>. It is inherited, and its |
| default value is 12 pt. If the user specifies the |
| <literal>font-size</literal> value as a percentage, then the actual |
| value is calculated from the <literal>font-size</literal> value |
| inherited from the parent FO node.</para> |
| |
| </section> |
| |
| <section> |
| <title>Shorthand properties</title> |
| |
| <section> |
| <title>Overview</title> |
| |
| <para>Shorthand properties are properties which are shorthand |
| for a number of properties. In other words, they specify the value of |
| a number of properties in a single attribute. All shorthand properties |
| can take a list of values, which are space separated in the FO |
| file. The FO spec specifies how this list of values determines the |
| values of the properties for which this is the shorthand (the target |
| properties.). The length of the list of values for a single shorthand |
| property may vary. For each length the attribution of these values to |
| the target properties is different.</para> |
| |
| <para>When the FO tree is constructed, shorthand property |
| values are parsed and stored like any other property value. Because |
| the value can be a list, it is always of type |
| <literal>ListProperty</literal>.</para> |
| |
| <para>The meaning of shorthand properties is only dealt with when the |
| value of one of the target properties is retrieved. For that purpose |
| each target property maker knows the shorthand properties that may set |
| its value, and when the target property value is retrieved, its maker |
| checks with each of its shorthand property makers if it has a |
| value. Note that the value of a shorthand property is never retrieved |
| directly, because shorthand properties have no direct meaning for the |
| layout.</para> |
| |
| <para>When the shorthand property value has been retrieved, |
| the value for the target property must be extracted from the |
| list. That is done by a shorthand parser, which implements |
| <literal>ShorthandParser</literal>. There are two implementing types: |
| <literal>GenericShorthandParser</literal> and |
| <literal>BoxPropShorthandParser</literal>. Their method |
| <literal>convertValueForProperty</literal> knows how each specified value |
| determines the value of the possible target properties. A shorthand |
| parser object is added to the shorthand property maker when the maker |
| is created.</para> |
| |
| <para>Note that <literal>CompoundPropertyMaker</literal> also |
| has a member <literal>shorthandMaker</literal>. I am not sure if this |
| has anything to do with shorthand properties. It seems more related to |
| <literal>CompoundPropertyMaker</literal> delegating certain tasks to a |
| subproperty maker, viz. the one which is the |
| <literal>shorthandMaker</literal>.</para> |
| |
| |
| </section> |
| |
| <section> |
| <title>Example of a shorthand property</title> |
| |
| <para>The property <literal>margin</literal> is shorthand for |
| the four properties <literal>margin-top</literal>, |
| <literal>margin-right</literal>, <literal>margin-bottom</literal>, |
| <literal>margin-left</literal>. Its value can consist of 1 to 4 width |
| values.</para> |
| |
| <para>When the property maker for <literal>margin</literal> is |
| created, it gets a <literal>BoxPropShorthandParser</literal> as |
| shorthand parser: |
| <screen> |
| m = new ListProperty.Maker(PR_MARGIN); |
| m.setInherited(false); |
| m.setDefault(""); |
| m.setDatatypeParser(new BoxPropShorthandParser()); |
| m.setPercentBase(LengthBase.BLOCK_WIDTH); |
| addPropertyMaker("margin", m); |
| </screen> |
| |
| When the property maker for <literal>margin-top</literal> is created, |
| the <literal>margin</literal> maker is registered with it as a |
| shorthand maker: |
| <screen> |
| m = new LengthProperty.Maker(PR_MARGIN_TOP); |
| m.setInherited(false); |
| m.setDefault("0pt"); |
| m.addShorthand(s_generics[PR_MARGIN]); |
| m.setPercentBase(LengthBase.BLOCK_WIDTH); |
| addPropertyMaker("margin-top", m); |
| </screen> |
| </para> |
| |
| <para>The maker for <literal>border-top-width</literal> has |
| three shorthands: <literal>border-top</literal>, |
| <literal>border-width</literal>, and <literal>border</literal>: |
| <screen> |
| this.shorthands = instance of org.apache.fop.fo.properties.PropertyMaker[3] (id=772) |
| this.shorthands[0] = "org.apache.fop.fo.properties.ListProperty$Maker@1e1dadb" |
| this.shorthands[0].propId = 52 |
| this.shorthands[1] = "org.apache.fop.fo.properties.ListProperty$Maker@bac9b9" |
| this.shorthands[1].propId = 56 |
| this.shorthands[2] = "org.apache.fop.fo.properties.ListProperty$Maker@8ceeea" |
| this.shorthands[2].propId = 18 |
| </screen></para> |
| |
| </section> |
| |
| <section> |
| <title>Parsing a shorthand property</title> |
| |
| <para>The value of a shorthand property is parsed and the value of a |
| target property is extracted in this call stack: |
| |
| <screen> |
| [1] org.apache.fop.fo.BoxPropShorthandParser.convertValueForProperty (BoxPropShorthandParser.java:80) |
| [2] org.apache.fop.fo.GenericShorthandParser.getValueForProperty (GenericShorthandParser.java:93) |
| [3] org.apache.fop.fo.properties.PropertyMaker.getShorthand (PropertyMaker.java:617) |
| [4] org.apache.fop.fo.properties.PropertyMaker.findProperty (PropertyMaker.java:277) |
| [5] org.apache.fop.fo.properties.PropertyMaker.get (PropertyMaker.java:305) |
| [6] org.apache.fop.fo.PropertyList.get (PropertyList.java:282) |
| [7] org.apache.fop.fo.PropertyList.get (PropertyList.java:268) |
| [8] org.apache.fop.fo.PropertyManager.getMarginProps (PropertyManager.java:301) |
| </screen> |
| </para> |
| |
| <para>The extraction proceeds as follows: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>PropertyMaker.getShorthand</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>parser.getValueForProperty(propId, |
| listprop, propertyMaker, propertyList)</literal>; |
| <literal>propId</literal> is the ID of the target property, |
| <literal>listprop</literal> is the shorthand property value, of type |
| <literal>ListProperty</literal>, which was retrieved <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>if the shorthand value is |
| <literal>inherit</literal>, get the value for the target property from |
| the parent.</para> |
| </listitem> |
| <listitem> |
| <para>else |
| <literal>convertValueForProperty(propId, listProperty, maker, |
| propertyList)</literal> <itemizedlist spacing="compact"> |
| <listitem> |
| <para>get from the shorthand list of |
| values the value that corresponds to the target property</para> |
| </listitem> |
| <listitem> |
| <para>if the retrieved value is not |
| <literal>null</literal>, convert the property, |
| <literal>maker.convertShorthandProperty(propertyList, p, |
| null)</literal> <itemizedlist spacing="compact"> |
| <listitem> |
| <para>first try to convert it in |
| the normal way: <literal>maker.convertProperty(prop, propertyList, |
| fo)</literal></para> |
| </listitem> |
| <listitem> |
| <para>if this gives a |
| <literal>null</literal> value, test if the value is an enumerated |
| value or a keyword; if so, process it.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| |
| </section> |
| |
| </section> |
| |
| <section> |
| <title>Corresponding properties</title> |
| |
| <para>A number of traits can be specified by two alternative |
| properties, e.g. <literal>border-left-width</literal> and |
| <literal>border-start-width</literal>. These are called corresponding |
| properties. One of a pair of corresponding properties is an absolute |
| property, the other is a relative property. The meaning of the |
| relative property depends on the writing mode. When the value of a |
| property is retrieved that has a corresponding property, the value of |
| that corresponding property should also be taken into account.</para> |
| |
| <para>Corresponding properties are registered with the property |
| maker when it is created: |
| |
| <screen> |
| bwm = new BorderWidthPropertyMaker(PR_BORDER_LEFT_WIDTH); |
| bwm.useGeneric(genericBorderWidth); |
| bwm.setBorderStyleId(PR_BORDER_LEFT_STYLE); |
| bwm.addShorthand(s_generics[PR_BORDER_LEFT]); |
| bwm.addShorthand(s_generics[PR_BORDER_WIDTH]); |
| bwm.addShorthand(s_generics[PR_BORDER]); |
| corr = new CorrespondingPropertyMaker(bwm); |
| corr.setCorresponding(PR_BORDER_START_WIDTH, PR_BORDER_END_WIDTH, |
| PR_BORDER_AFTER_WIDTH); |
| addPropertyMaker("border-left-width", bwm); |
| </screen> |
| |
| There are always three corresponding properties, for the three writing |
| modes <literal>lr_tb</literal>, <literal>rl_tb</literal>, |
| <literal>tb_rl</literal>, in this order: |
| |
| <screen> |
| corr = { |
| baseMaker: instance of org.apache.fop.fo.properties.BorderWidthPropertyMaker(id=702) |
| lr_tb: 50 |
| rl_tb: 36 |
| tb_rl: 22 |
| useParent: false |
| relative: false |
| } |
| </screen> |
| </para> |
| |
| <para>When a property value is retrieved, the value of the |
| corresponding property may have priority. This is determined by the |
| method <literal>corresponding.isCorrespondingForced()</literal>. This |
| is true if |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>this is a relative property</para> |
| </listitem> |
| <listitem> |
| <para>and the corresponding property has been explicitly |
| specified on this FO node</para> |
| </listitem> |
| </itemizedlist> |
| Relative properties are marked by the fact that their corresponding |
| property maker has its member <literal>relative</literal> set to |
| <literal>true</literal>; this is set when the property is |
| created.</para> |
| |
| <para>If the corresponding property has priority, its value is |
| computed. Otherwise, if the value of the property itself has been |
| explicitly specified on this FO node, it is used. Otherwise, the |
| corresponding property is computed. Computation in this connection |
| means that also the shorthand properties are checked.</para> |
| |
| <para>Because shorthand properties only exist for absolute properties, |
| the values are effectively checked in this order: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>An absolute property <itemizedlist spacing="compact"> |
| <listitem> |
| <para>The explicit value of this property.</para> |
| </listitem> |
| <listitem> |
| <para>The explicit value of the corresponding |
| property.</para> |
| </listitem> |
| <listitem> |
| <para>The value of this property from the shorthand |
| properties.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| |
| <listitem> |
| <para>A relative property <itemizedlist spacing="compact"> |
| <listitem> |
| <para>The explicit value of the corresponding |
| property.</para> |
| </listitem> |
| <listitem> |
| <para>The explicit value of this property.</para> |
| </listitem> |
| <listitem> |
| <para>The value of the corresponding property from |
| the shorthand properties.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist> |
| </para> |
| |
| </section> |
| |
| <section> |
| <title>Mapping between property names, IDs and makers</title> |
| |
| <para>The property subsystem is set up in the class |
| <literal>FOPropertyMapping</literal>. It creates a property maker |
| object for each property type, and it creates mappings of |
| the names, IDs and makers of the property types. It holds the |
| following static maps: |
| |
| <screen> |
| property name <=> property ID => property maker |
| | | |
| s_htSubPropNames (<-) s_htGeneric |
| s_htPropIds (->) |
| </screen> |
| |
| Each type of FObj holds a copy of <literal>s_htGeneric</literal> as |
| its static member <literal>FObj.propertyListTable</literal>. According |
| to design documents an FObj type may have its own specific makers for |
| certain property types. Probably this is the reason that |
| <literal>FObj</literal> holds its own copy of the list of makers. This |
| allows subclasses to hold their own modified copy. As far as I know, |
| this is not currently the case.</para> |
| |
| <para>The mappings are filled in the static method |
| |
| <screen> |
| private static void addPropertyMaker(String name, Property.Maker maker) { |
| s_generics[maker.getPropId()] = maker; |
| s_htPropNames.put(name, new Integer(maker.getPropId())); |
| s_htPropIds.put(new Integer(maker.getPropId()), name); |
| } |
| </screen> |
| |
| which is called for each property type.</para> |
| |
| <para>The constants for property IDs are defined in the interface |
| <literal>org.apache.fop.fo.Constants</literal>: |
| |
| <screen> |
| int PR_ABSOLUTE_POSITION = 1; |
| int PR_ACTIVE_STATE = 2; |
| ... |
| int PR_FONT_SIZE = 94; |
| ... |
| int PROPERTY_COUNT = 247; |
| </screen> |
| </para> |
| |
| <para>Composite properties are defined by a compound number: |
| |
| <screen> |
| int COMPOUND_SHIFT = 9; |
| int CP_MAXIMUM = 5 << COMPOUND_SHIFT; |
| int CP_MINIMUM = 6 << COMPOUND_SHIFT; |
| int CP_OPTIMUM = 7 << COMPOUND_SHIFT; |
| ... |
| </screen> |
| </para> |
| |
| <para>Enumerated property values are also defined here: |
| |
| <screen> |
| int ABSOLUTE = 1; |
| int ABSOLUTE_COLORMETRIC = 2; |
| ... |
| int VISIBLE = 105; |
| int WRAP = 106; |
| </screen></para> |
| |
| <para>For fast access to important characteristic of property |
| inheritance, <literal>PropertyList</literal> maintains a static array |
| <literal>boolean[Constants.PROPERTY_COUNT + 1] |
| inheritableProperty</literal>, which lists for each property type if |
| it is inherited. It is constructed by asking the maker of each |
| property type if it is inherited.</para> |
| |
| <para>A few members of the array of <literal>PropertyMaker</literal>s |
| <literal>s_generics</literal>. It is indexed by the |
| <literal>propID</literal>. Member 0 is <literal>null</literal>, and |
| serves for unknown property types. Member 1 is for |
| <literal>absolute-position</literal>, member 94 for |
| <literal>font-size</literal>. |
| |
| <screen> |
| main[1] print org.apache.fop.fo.FOPropertyMapping.s_generics |
| org.apache.fop.fo.FOPropertyMapping.s_generics = instance of org.apache.fop.fo.Property$Maker[248] (id=651) |
| main[1] print org.apache.fop.fo.FOPropertyMapping.s_generics[0] |
| org.apache.fop.fo.FOPropertyMapping.s_generics[0] = null |
| main[1] print org.apache.fop.fo.FOPropertyMapping.s_generics[1] |
| org.apache.fop.fo.FOPropertyMapping.s_generics[1] = "org.apache.fop.fo.EnumProperty$Maker@12884e0" |
| main[1] print org.apache.fop.fo.FOPropertyMapping.s_generics[94] |
| org.apache.fop.fo.FOPropertyMapping.s_generics[94] = "org.apache.fop.fo.LengthProperty$Maker@32efa7" |
| </screen> |
| </para> |
| |
| <para>A few members of the mapping <literal>s_htPropIds</literal> |
| from <literal>propID</literal> to property name. The |
| <literal>s_htPropIds</literal> for compound properties are shifted: |
| |
| <screen> |
| main[1] print org.apache.fop.fo.FOPropertyMapping.s_htPropIds |
| org.apache.fop.fo.FOPropertyMapping.s_htPropIds = "{ |
| 1=absolute-position |
| ... |
| 94=font-size |
| ... |
| 247=z-index |
| 512=block-progression-direction |
| 1024=conditionality |
| ... |
| 5632=within-page |
| }" |
| </screen> |
| </para> |
| |
| <para>A few members of the mappings <literal>s_htPropNames</literal> |
| and <literal>s_htSubPropNames</literal> from property name to |
| <literal>propID</literal>. The <literal>propIds</literal> for |
| compound properties are shifted: |
| |
| <screen> |
| main[1] print org.apache.fop.fo.FOPropertyMapping.s_htPropNames |
| org.apache.fop.fo.FOPropertyMapping.s_htPropNames = "{ |
| absolute-position=1 |
| ... |
| font-size=94 |
| ... |
| z-index=247 |
| }" |
| </screen> |
| |
| <screen> |
| main[1] print org.apache.fop.fo.FOPropertyMapping.s_htSubPropNames |
| org.apache.fop.fo.FOPropertyMapping.s_htSubPropNames = "{ |
| block-progression-direction=512 |
| conditionality=1024 |
| ... |
| within-page=5632 |
| }" |
| </screen> |
| </para> |
| |
| </section> |
| |
| <section> |
| <title>Storing the property values based on their |
| <literal>PropID</literal></title> |
| |
| <para>The class <literal>PropertySets</literal> contains a setup |
| by which property values may be retrieved by their |
| <literal>PropId</literal> instead of their name. In this setup |
| <literal>PropertyList</literal> no longer extends |
| <literal>HashMap</literal> but contains an array of property objects, |
| called <literal>values</literal>. In order to prevent that each FObj |
| should contain an array of size |
| <literal>Constants.PROPERTY_COUNT</literal>, a mapping is setup from a |
| static array for all FO types and all property types to an index for |
| the possible properties of an FO type, |
| <literal>PropertySets.mapping</literal>.</para> |
| |
| <para><literal>PropertySets.mapping</literal> is a |
| <literal>short[Constants.ELEMENT_COUNT+1][]</literal> matrix, which |
| for each FO type contains a mapping from <literal>PropID</literal> to |
| a sparse array of indices, which enumerates the properties that are |
| valid for this FO type.</para> |
| |
| <para>For an element <literal>fo:bar</literal> which supports 2 |
| properties, <literal>foo</literal>, whose <literal>PropID</literal> is |
| 21, and <literal>baz</literal>, whose <literal>PropID</literal> is |
| 137, the array of indices has the values |
| |
| <screen> |
| indices[21] = 1 |
| indices[137] = 2 |
| </screen> |
| |
| and all other values are 0. Here indices denotes the row in |
| <literal>mapping</literal> which corresponds to FO type bar.</para> |
| |
| <para>The values are indices into the array |
| <literal>PropertyList.values</literal>, which then looks like this: |
| |
| <screen> |
| values[0] = null // always null. |
| values[1] = reference to a 'foo' Property instance |
| values[2] = reference to a 'baz' Property instance |
| </screen> |
| </para> |
| |
| <para>Example of <literal>PropertySets.mapping</literal>: |
| |
| <screen> |
| PropID -> | 0 1 2 3 4 5 ... (Contants.PR_XXX) |
| Element | | |
| v | |
| -----------------|-------------------------------------------------- |
| FO_BASIC_LINK | 2 0 1 0 2 0 |
| FO_BIDI_OVERRIDE | 3 0 0 1 2 3 |
| FO_BLOCK | 2 1 0 0 2 0 |
| ... | .... |
| | |
| </screen> |
| </para> |
| |
| <para>A property value of an <literal>FONode</literal> can then be |
| retrieved as <literal>PropertyList.values[indices[propId]]</literal>, |
| where <literal>indices = PropertySets.getPropertySet(elementId) = |
| PropertySets.mapping[elementId].</literal></para> |
| |
| <para>The matrix <literal>PropertySets.mapping</literal> is |
| constructed in the routine |
| <literal>PropertySets.initialize()</literal>.</para> |
| |
| <para>First it constructs the <literal>elements</literal> array. For |
| each FO type this array contains an <literal>Element</literal> |
| object. This object contains a list of properties which are valid for |
| this type of FO, and a list of child <literal>Element</literal> |
| objects. Each child <literal>Element</literal> object corresponds to |
| an FO type that may occur as a child of this FO type.</para> |
| |
| <para>Then the <literal>for (boolean dirty = true; dirty; )</literal> |
| loop is executed. It effect is as follows (from an email by Finn |
| Bock). For each FO type the <literal>BitSet</literal> of allowed |
| properties is merged with the <literal>BitSet</literal> of allowed |
| properties of its possible direct children. When for any FO type the |
| <literal>merge</literal> subroutine modifies its |
| <literal>BitSet</literal>, it sets the boolean variable |
| <literal>dirty</literal> to <literal>true</literal> to signal that |
| another iteration of the loop is required. By iterating over the loop |
| until no further modifications are made, one makes sure that the |
| merging process propagates from below to the top, that is, from any FO |
| type to its farthest possible ancestor. This ensures that every FO |
| type registers the allowed properties of itself and of all FO types |
| that may ever appear in its subtree.</para> |
| |
| <para>The matrix <literal>PropertySets.mapping</literal> is still not |
| used in <literal>PropertyList</literal>, and the array |
| <literal>values</literal> does not yet exist (19 May 2004). The |
| properties are held by name in <literal>PropertyList</literal>, which |
| extends <literal>HashMap</literal>.</para> |
| |
| </section> |
| |
| </section> |
| |
| <section id="sec.properties.create"> |
| <title>Creating a property value</title> |
| |
| <section> |
| <title>General</title> |
| |
| <para>A property value is created by the maker for the property type, |
| in its method |
| <literal>PropertyMaker.make(PropertyList, String, FObj)</literal>, |
| where the second argument is the property value as a string: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>If the specified value is <literal>inherit</literal>, |
| get the property value from the parent FObj.</para> |
| </listitem> |
| <listitem> |
| <para>Else if the value is an enumerated value, the corresponding |
| property value is retrieved (for each possible enumerated value only |
| one property value object exists, of type EnumProperty).</para> |
| </listitem> |
| <listitem> |
| <para>If this does not retrieve a property value, <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>If the value is a shorthand keyword, it is |
| converted to the corresponding value.</para> |
| </listitem> |
| <listitem> |
| <para>The value is parsed, and a property value is |
| created.</para> |
| </listitem> |
| <listitem> |
| <para>The method |
| <literal>PropertyMaker.convertProperty</literal> is called, which is overridden |
| in subclasses of PropertyMaker. CompoundPropertyMaker uses this method |
| to convert the simple property value constructed to a compound |
| property value: <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Make a compound property value based on |
| default values: <literal>PropertyMaker.makeCompound</literal>, |
| overridden in CompoundPropertyMaker.</para> |
| </listitem> |
| <listitem> |
| <para>Set all components equal to the |
| simple property value that is being converted.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>If this is a compound property maker, convert it to |
| a compound property as above. (Is this the second time the property |
| value is converted?)</para> |
| </listitem> |
| </itemizedlist> |
| The property may also record the value as specified in the fo element, |
| as this may influence the traits of the areas created by this FO node |
| and FO nodes in the subtree.</para> |
| |
| <para>Subclasses of <literal>PropertyMaker</literal> may override this |
| method. For example, <literal>StringProperty.Maker</literal> has a |
| much simpler method.</para> |
| |
| <para>Attributes of the fo elements are converted to property value |
| objects in <literal>PropertyList.convertAttributeToProperty</literal>: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>If the property is not a component of a compound |
| property, <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Ask the maker for the property to create the |
| property value.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>Else if the property is a component of a compound |
| property, <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Find the base property by a call to |
| <literal>Propertylist.findBaseProperty</literal>: <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>If the base property value already exists, |
| return it to <literal>convertAttributeToProperty</literal>.</para> |
| </listitem> |
| <listitem> |
| <para>If the base attribute is also specified |
| (later) in the list of attributes, retrieve it, ask the maker for the |
| base property to create the base property value, and return it to |
| <literal>convertAttributeToProperty</literal>.</para> |
| </listitem> |
| <listitem> |
| <para>Return |
| null to <literal>convertAttributeToProperty</literal>.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>Ask the maker for the subproperty to create the |
| subproperty value by a call to <literal>PropertyMaker.make(Property, |
| int, PropertyList, String, FObj)</literal>, where the second argument |
| is the subproperty ID and the fourth argument is the specified |
| value. This method is overridden in |
| <literal>CompoundPropertyMaker</literal>: <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>If the base property value does not yet |
| exist, ask its maker to create it with default values for the |
| components: <literal>PropertyMaker.makeCompound</literal>, which is |
| overridden in <literal>CompoundPropertyMaker</literal>: <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>Create an empty property value.</para> |
| </listitem> |
| <listitem> |
| <para>Create property values for the |
| subproperties with default values, and insert them into the compound |
| property value.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>Create the specified subproperty value and |
| insert it into the compound property value, where it replaces the |
| default subproperty value.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>Add the property to the property list. |
| </para> |
| </listitem> |
| </itemizedlist></para> |
| |
| </section> |
| |
| <section> |
| <title>Example of a compound property</title> |
| |
| <para>In this example we illustrate the case where first the |
| base attribute of a compound property is specified, and then the |
| attribute for one of the components.</para> |
| |
| <para>First the user specifies the attribute value |
| <literal>leader-length="120pt"</literal>.</para> |
| |
| <para>A simple length property value is constructed first: |
| <screen> |
| p.getClass() = "class org.apache.fop.fo.properties.FixedLength" |
| p = { |
| millipoints: 120000 |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| p = "120000mpt" |
| </screen></para> |
| |
| <para>Then it is converted into a compound property value. First a |
| compound property with default component values is created: |
| <screen> |
| p.getClass() = "class org.apache.fop.fo.properties.LengthRangeProperty" |
| p = { |
| minimum: instance of org.apache.fop.fo.properties.FixedLength(id=759) |
| optimum: instance of org.apache.fop.fo.properties.FixedLength(id=760) |
| maximum: instance of org.apache.fop.fo.properties.PercentLength(id=761) |
| bfSet: 0 |
| bChecked: true |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| p = "LengthRange[min:0mpt, max:100.0%, opt:12000mpt]" |
| </screen> |
| |
| Then all components are set equal to the simple property value: |
| <screen> |
| prop.getClass() = "class org.apache.fop.fo.properties.LengthRangeProperty" |
| prop = { |
| minimum: instance of org.apache.fop.fo.properties.FixedLength(id=744) |
| optimum: instance of org.apache.fop.fo.properties.FixedLength(id=744) |
| maximum: instance of org.apache.fop.fo.properties.FixedLength(id=744) |
| bfSet: 7 |
| bChecked: true |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| prop = "LengthRange[min:120000mpt, max:120000mpt, opt:120000mpt]" |
| </screen></para> |
| |
| <para>The property makers involved: |
| <screen> |
| this = "org.apache.fop.fo.properties.LengthRangeProperty$Maker@55a338" |
| this.subproperties = instance of org.apache.fop.fo.properties.PropertyMaker[11] (id=766) |
| getSubpropMaker(org.apache.fop.fo.Constants.CP_MINIMUM) = "org.apache.fop.fo.properties.LengthProperty$Maker@955cd5" |
| getSubpropMaker(org.apache.fop.fo.Constants.CP_MAXIMUM) = "org.apache.fop.fo.properties.LengthProperty$Maker@1bde4" |
| getSubpropMaker(org.apache.fop.fo.Constants.CP_OPTIMUM) = "org.apache.fop.fo.properties.LengthProperty$Maker@a77106" |
| </screen></para> |
| |
| <para>Stack dump when making the compound property: |
| <screen> |
| [1] org.apache.fop.fo.properties.CompoundPropertyMaker.makeCompound (CompoundPropertyMaker.java:258) |
| [2] org.apache.fop.fo.properties.CompoundPropertyMaker.convertProperty (CompoundPropertyMaker.java:173) |
| [3] org.apache.fop.fo.properties.LengthRangeProperty$Maker.convertProperty (LengthRangeProperty.java:68) |
| [4] org.apache.fop.fo.properties.PropertyMaker.make (PropertyMaker.java:392) |
| [5] org.apache.fop.fo.properties.CompoundPropertyMaker.make (CompoundPropertyMaker.java:206) |
| [6] org.apache.fop.fo.PropertyList.convertAttributeToProperty (PropertyList.java:418) |
| [7] org.apache.fop.fo.PropertyList.addAttributesToList (PropertyList.java:374) |
| [8] org.apache.fop.fo.FObj.addProperties (FObj.java:133) |
| [9] org.apache.fop.fo.FObj.processNode (FObj.java:96) |
| [10] org.apache.fop.fo.FOTreeBuilder.startElement (FOTreeBuilder.java:234) |
| </screen> |
| </para> |
| |
| <para>Subsequently, the user specifies a component, |
| <literal>leader-length.maximum="200pt"</literal>.</para> |
| |
| <para>First the subproperty is constructed as a simple length property: |
| <screen> |
| p.getClass() = "class org.apache.fop.fo.properties.FixedLength" |
| p = { |
| millipoints: 200000 |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| p = "200000mpt" |
| </screen> |
| </para> |
| |
| <para>Then it is added to the compound property as the component |
| <literal>maximum</literal>: |
| <screen> |
| prop.getClass() = "class org.apache.fop.fo.properties.LengthRangeProperty" |
| prop = { |
| minimum: instance of org.apache.fop.fo.properties.FixedLength(id=755) |
| optimum: instance of org.apache.fop.fo.properties.FixedLength(id=755) |
| maximum: instance of org.apache.fop.fo.properties.FixedLength(id=767) |
| bfSet: 7 |
| bChecked: true |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| prop = "LengthRange[min:120000mpt, max:200000mpt, opt:120000mpt]" |
| </screen> |
| </para> |
| |
| <para>Stack dump when making the property: |
| <screen> |
| [1] org.apache.fop.fo.properties.PropertyMaker.make (PropertyMaker.java:378) |
| [2] org.apache.fop.fo.properties.CompoundPropertyMaker.make (CompoundPropertyMaker.java:235) |
| [3] org.apache.fop.fo.PropertyList.convertAttributeToProperty (PropertyList.java:423) |
| [4] org.apache.fop.fo.PropertyList.addAttributesToList (PropertyList.java:374) |
| [5] org.apache.fop.fo.FObj.addProperties (FObj.java:133) |
| [6] org.apache.fop.fo.FObj.processNode (FObj.java:96) |
| [7] org.apache.fop.fo.FOTreeBuilder.startElement (FOTreeBuilder.java:234) |
| </screen></para> |
| |
| </section> |
| |
| <section> |
| <title>Enumerated property values</title> |
| |
| <para>The interface <literal>Constants</literal> defines values |
| for each possible enumerated value of a property: |
| <screen> |
| int ABSOLUTE = 1; |
| int ABSOLUTE_COLORMETRIC = 2; |
| ... |
| int VISIBLE = 105; |
| int WRAP = 106; |
| </screen></para> |
| |
| <para>In <literal>FOPropertyMapping</literal> a property value |
| object is constructed for each possible enumerated value. See the |
| <literal>Property</literal> array <literal>enums</literal> and the |
| method <literal>makeEnumProperty</literal>. During its construction, |
| each property maker that can have enumerated values gets a member |
| <literal>enums</literal>, which, for each of its possible enumerated |
| values, gets a reference to the appropriate enumerated property value |
| object. See the method <literal>PropertyMaker.addEnum</literal>.</para> |
| |
| <para>Example: The properties <literal>hyphenate</literal> and |
| <literal>precedence</literal> both have the possible value |
| <literal>true</literal>. Their makers have a reference to the same |
| property value object: |
| <screen> |
| org.apache.fop.fo.FOPropertyMapping.s_generics |
| [org.apache.fop.fo.Constants.PR_HYPHENATE]. |
| enums.get("true").hashCode() = 9236202 |
| org.apache.fop.fo.FOPropertyMapping.s_generics |
| [org.apache.fop.fo.Constants.PR_PRECEDENCE]. |
| enums.get("true").hashCode() = 9236202 |
| org.apache.fop.fo.FOPropertyMapping.s_generics |
| [org.apache.fop.fo.Constants.PR_HYPHENATE].enums.get("true") = "100" |
| org.apache.fop.fo.FOPropertyMapping.s_generics |
| [org.apache.fop.fo.Constants.PR_HYPHENATE].enums.get("true") = { |
| value: 100 |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| </screen></para> |
| |
| <para>Example: <literal>leader-pattern="rule"</literal>. |
| <screen> |
| this = "org.apache.fop.fo.properties.EnumProperty$Maker@25c828" |
| this.enums = "{rule=82, use-content=104, dots=21, space=88}" |
| this.enums.get("rule").getClass() = "class org.apache.fop.fo.properties.EnumProperty" |
| this.enums.get("rule") = "82" |
| this.enums.get("rule") = { |
| value: 82 |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| </screen></para> |
| |
| <para>The maker's method <literal>checkEnumValues</literal> returns |
| the appropriate property value object |
| <literal>enums.get(value)</literal>: <literal>newProp = |
| "82"</literal>.</para> |
| |
| <screen> |
| [1] org.apache.fop.fo.properties.PropertyMaker.checkEnumValues (PropertyMaker.java:480) |
| [2] org.apache.fop.fo.properties.EnumProperty$Maker.checkEnumValues (EnumProperty.java:50) |
| [3] org.apache.fop.fo.properties.PropertyMaker.make (PropertyMaker.java:383) |
| [4] org.apache.fop.fo.PropertyList.convertAttributeToProperty (PropertyList.java:418) |
| [5] org.apache.fop.fo.PropertyList.addAttributesToList (PropertyList.java:374) |
| </screen> |
| |
| </section> |
| |
| <section> |
| <title>Example of a property with keywords</title> |
| |
| <para>The value of the property <literal>border-top-width</literal> |
| can be set to a width, but it can also be indicated by one of the |
| keywords <literal>thin</literal>, <literal>medium</literal> and |
| <literal>thick</literal>. The width values to which these keywords |
| correspond are by default set by the implementation. When the property |
| maker is constructed in <literal>FOPropertyMapping</literal>, it gets |
| a hash map of keyword values. |
| <screen> |
| this = "org.apache.fop.fo.properties.BorderWidthPropertyMaker@1cf4a2c" |
| this.propId = 55 |
| this.keywords = "{medium=1pt, thin=0.5pt, thick=2pt}" |
| } |
| </screen> |
| </para> |
| |
| <para>The method <literal>checkValueKeywords</literal> returns the |
| mapped value: <literal>value = "1pt"</literal>. Subsequently a |
| property value object is created as if that value had been specified. |
| |
| <screen> |
| [1] org.apache.fop.fo.properties.PropertyMaker.checkValueKeywords (PropertyMaker.java:499) |
| [2] org.apache.fop.fo.properties.PropertyMaker.make (PropertyMaker.java:387) |
| [3] org.apache.fop.fo.PropertyList.convertAttributeToProperty (PropertyList.java:418) |
| [4] org.apache.fop.fo.PropertyList.addAttributesToList (PropertyList.java:374) |
| [5] org.apache.fop.fo.FObj.addProperties (FObj.java:133) |
| </screen> |
| </para> |
| |
| </section> |
| |
| <section> |
| <title>Parsing a property with an absolute value</title> |
| |
| <para>Property values are parsed in |
| <literal>PropertyParser.parseProperty</literal>: |
| <screen> |
| [1] org.apache.fop.fo.expr.PropertyParser.parseProperty (PropertyParser.java:111) |
| [2] org.apache.fop.fo.expr.PropertyParser.parse (PropertyParser.java:88) |
| [3] org.apache.fop.fo.properties.PropertyMaker.make (PropertyMaker.java:389) |
| [4] org.apache.fop.fo.PropertyList.convertAttributeToProperty (PropertyList.java:418) |
| [5] org.apache.fop.fo.PropertyList.addAttributesToList (PropertyList.java:374) |
| [6] org.apache.fop.fo.FObj.addProperties (FObj.java:133) |
| </screen></para> |
| |
| <para>Example: <literal><fo:simple-page-master |
| master-name="simpleA4" margin="4pt"></literal>, property being parsed: |
| <literal>margin="4pt"</literal>, <literal>propId</literal> = 134.</para> |
| |
| <para>The PropertyParser object: |
| <screen> |
| this = "org.apache.fop.fo.expr.PropertyParser@8530b8" |
| this = { |
| propInfo: instance of org.apache.fop.fo.expr.PropertyInfo(id=729) |
| org.apache.fop.fo.expr.PropertyTokenizer.currentToken: 0 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenValue: null |
| org.apache.fop.fo.expr.PropertyTokenizer.currentUnitLength: 0 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenStartIndex: 0 |
| org.apache.fop.fo.expr.PropertyTokenizer.expr: "4pt" |
| org.apache.fop.fo.expr.PropertyTokenizer.exprIndex: 0 |
| org.apache.fop.fo.expr.PropertyTokenizer.exprLength: 3 |
| org.apache.fop.fo.expr.PropertyTokenizer.recognizeOperator: false |
| } |
| </screen></para> |
| |
| <para>It has a member of type <literal>PropertyInfo</literal>, |
| which contains contextual information: |
| <screen> |
| propInfo = "org.apache.fop.fo.expr.PropertyInfo@1abcc03" |
| propInfo = { |
| maker: instance of org.apache.fop.fo.properties.ListProperty$Maker(id=705) |
| plist: instance of org.apache.fop.fo.PropertyList(id=737) |
| fo: instance of org.apache.fop.fo.pagination.LayoutMasterSet(id=738) |
| stkFunction: null |
| } |
| </screen> |
| <literal>fo</literal> is the parent FO.</para> |
| |
| <para>The property list of the current FO node: |
| <screen> |
| propInfo.plist = { |
| writingModeTable: null |
| writingMode: 0 |
| inheritableProperty: null |
| parentPropertyList: instance of org.apache.fop.fo.PropertyList(id=743) |
| namespace: "http://www.w3.org/1999/XSL/Format" |
| elementName: "fo:simple-page-master" |
| fobj: instance of org.apache.fop.fo.pagination.SimplePageMaster(id=746) |
| } |
| </screen> |
| The property list up to now: |
| <screen> |
| propInfo.plist = "{master-name=simpleA4}" |
| </screen> |
| </para> |
| |
| <para>Property <literal>master-name</literal>'s maker is |
| <literal>StringPropertyMaker</literal>, which does not parse its |
| value.</para> |
| |
| <para>PropertyParser.parseProperty <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>next(), which scans the next token; at its return: |
| <screen> |
| this = { |
| propInfo: instance of org.apache.fop.fo.expr.PropertyInfo(id=667) |
| org.apache.fop.fo.expr.PropertyTokenizer.currentToken: 12 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenValue: "4pt" |
| org.apache.fop.fo.expr.PropertyTokenizer.currentUnitLength: 2 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenStartIndex: 0 |
| org.apache.fop.fo.expr.PropertyTokenizer.expr: "4pt" |
| org.apache.fop.fo.expr.PropertyTokenizer.exprIndex: 3 |
| org.apache.fop.fo.expr.PropertyTokenizer.exprLength: 3 |
| org.apache.fop.fo.expr.PropertyTokenizer.recognizeOperator: true |
| } |
| </screen> |
| i.e. the whole expression is a single token, it is of type |
| <literal>PropertyTokenizer.TOK_NUMERIC</literal> (= 12), the unit is 2 |
| chars long.</para> |
| </listitem> |
| <listitem> |
| <para>Loop forever. <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>Analyse the expression. Start with |
| <literal>parseAdditiveExpr</literal> <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>parseMultiplicativeExpr</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>parseUnaryExpr</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>parsePrimaryExpr</literal>; |
| the unit may be a relative unit (em) which must be resolved against |
| the font size <itemizedlist spacing="compact"> |
| <listitem> |
| <para>construct a property |
| value object: |
| <screen> |
| prop = "4000mpt" |
| prop.getClass() = "class org.apache.fop.fo.properties.FixedLength" |
| </screen></para> |
| </listitem> |
| <listitem> |
| <para><literal>next()</literal>: |
| scan the next token; |
| <screen> |
| this = { |
| propInfo: instance of org.apache.fop.fo.expr.PropertyInfo(id=729) |
| org.apache.fop.fo.expr.PropertyTokenizer.currentToken: 0 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenValue: null |
| org.apache.fop.fo.expr.PropertyTokenizer.currentUnitLength: 2 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenStartIndex: 3 |
| org.apache.fop.fo.expr.PropertyTokenizer.expr: "4pt" |
| org.apache.fop.fo.expr.PropertyTokenizer.exprIndex: 3 |
| org.apache.fop.fo.expr.PropertyTokenizer.exprLength: 3 |
| org.apache.fop.fo.expr.PropertyTokenizer.recognizeOperator: true |
| } |
| </screen> |
| the next token is of type <literal>currentToken = |
| PropertyTokenizer.TOK_EOF</literal>.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>If <literal>currentToken = |
| PropertyTokenizer.TOK_EOF</literal>, break the loop.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist> |
| Return the property: <literal>p = "4000mpt"</literal>.</para> |
| </section> |
| |
| </section> |
| |
| <section> |
| <title>Retrieving a property value</title> |
| |
| <section> |
| <title>Overview</title> |
| |
| <para>For all FO types the FO spec specifies a large number of |
| property types for which the user may specify a value in order to |
| modify the resulting layout of the document. Many of these properties |
| have a default value, many others inherit their value from the parent |
| FO if they are not specified. In principle the layout process must |
| retrieve the value of each possible property type of an FO node in |
| order to determine the appropriate value of the corresponding |
| trait.</para> |
| |
| <para>Retrieving a property value goes through these steps: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>First determine if the property value was specified |
| in one or other way. This is done in the method |
| <literal>propertyMaker.findProperty</literal> <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>if this property has a corresponding property |
| and if the corresponding property is forced, i.e. if this property is |
| relative and if a value for the corresponding property was explicitly |
| specified, compute and return it.</para> |
| </listitem> |
| <listitem> |
| <para>else <itemizedlist spacing="compact"> |
| <listitem> |
| <para>if a value for this property was |
| explicitly specified, compute and return it</para> |
| </listitem> |
| <listitem> |
| <para>else if this property has a |
| corresponding property, compute its value; if it is not null return |
| it</para> |
| </listitem> |
| <listitem> |
| <para>else if a value for a relevant shorthand |
| property was specified, compute and return it</para> |
| </listitem> |
| <listitem> |
| <para>else if this property is inheritable, |
| find it at the parent; this repeats the whole process on the parent, |
| and possibly its parents, up to the root node; if successful, return |
| the found property value</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>If no property value is found, a default property |
| value object is made; the default value is stored in the property |
| maker as <literal>defaultValue</literal>: <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>if the default property value object was |
| calculated earlier, it was cached as |
| <literal>defaultProperty</literal>; return it</para> |
| </listitem> |
| <listitem> |
| <para>else make it in the same way as property value |
| objects are made when the FO tree is constructed, in |
| <literal>propertyMaker.make</literal>.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| |
| <para>Compute corresponding, as used in |
| <literal>findProperty</literal>, proceeds as follows: <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>use parent's property list or this property |
| list?</para> |
| </listitem> |
| <listitem> |
| <para>check explicit or shorthand for corresponding</para> |
| </listitem> |
| <listitem> |
| <para>convert property</para> |
| </listitem> |
| </itemizedlist></para> |
| |
| <para><literal>PropertyManager</literal>, |
| <literal>CommonBorderAndPadding</literal>, |
| <literal>CommonBackground</literal>, |
| <literal>CommonMarginBlock</literal>, |
| <literal>CommonHyphenation</literal> are convenience classes used in |
| the calculation of the traits. <literal>PropertyManager</literal> has |
| methods to return objects of these types. A |
| <literal>CommonBorderAndPadding</literal> object and a |
| <literal>CommonHyphenation</literal> object are cached. A |
| <literal>CommonBackground</literal> object and a |
| <literal>CommonMarginBlock</literal> object are calculated when |
| requested. Similarly for many other convenience classes |
| <literal>Common*</literal> for which |
| <literal>PropertyManager</literal> can return an object. These classes |
| are in package <literal>fo.properties</literal>. Similar classes |
| called <literal>*Props</literal> are in package |
| <literal>traits</literal>. Of these <literal>PropertyManager</literal> |
| can only return a <literal>BlockProps</literal> object.</para> |
| |
| </section> |
| |
| <section> |
| <title>Detailed overview</title> |
| |
| <para>The retrieval of a property value is started with a call |
| to <literal>PropertyList.get(int propId)</literal>, which calls |
| <literal>PropertyList.get(propId, true, true)</literal>.</para> |
| |
| <para><literal>PropertyList.get(int propId, boolean bTryInherit, |
| boolean bTryDefault)</literal>: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Find the maker for this property as |
| <literal>FObj.propertyListTable[propId]</literal>, variable |
| <literal>propertyMaker</literal></para> |
| </listitem> |
| <listitem> |
| <para><literal>propertyMaker.get(int subpropId, |
| PropertyList propertyList, boolean bTryInherit, boolean |
| bTryDefault)</literal> <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>propertyMaker.findProperty(PropertyList |
| propertyList, boolean bTryInherit)</literal> <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>if corresponding and corresponding is |
| forced <itemizedlist spacing="compact"> |
| <listitem> |
| <para>evaluate condition: |
| <literal>CorrespondingPropertyMaker.isCorrespondingForced |
| (PropertyList propertyList)</literal> <itemizedlist spacing="compact"> |
| <listitem> |
| <para> <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>return false if this is |
| not a relative property |
| (<literal>corresponding.relative</literal>)</para> |
| </listitem> |
| <listitem> |
| <para>return true if |
| corresponding property was explicitly specified on this node or on its |
| parent, depending on the type of property |
| (<literal>corresponding.useParent</literal>)</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para><literal>corresponding.compute(PropertyList |
| propertyList)</literal>; this subroutine and the subroutines it calls |
| refer to the corresponding property <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>propertyList.getExplicitOrShorthand(correspondingId)</literal>; |
| propertyList is that of this node or of the parent, depending on the |
| type of property (corresponding.useParent) <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para><literal>propertyList.getExplicitBaseProp(int |
| correspondingId)</literal> (see below)</para> |
| </listitem> |
| <listitem> |
| <para>if |
| <literal>(null)</literal> <literal>propertyList.getShorthand(int |
| correspondingId)</literal> <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>propertyMaker.getShorthand(this)</literal> |
| (see below)</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>if <literal>(not |
| null)</literal> convert property</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>else <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>propertyList.getExplicitBaseProp(int |
| propId)</literal> from <literal>propertyList</literal> as a hash map; |
| note that this requires a conversion from <literal>propId</literal> to |
| <literal>propName</literal> via <literal>s_htPropNames</literal>; |
| example: <literal>propertyList = |
| "{master-name=simpleA4}"</literal></para> |
| </listitem> |
| <listitem> |
| <para>if <literal>(null)</literal> |
| <literal>propertyMaker.compute(PropertyList propertyList)</literal>: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>if |
| <literal>(corresponding)</literal> |
| <literal>corresponding.compute(PropertyList propertyList)</literal>, |
| as above</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>if <literal>(null)</literal> |
| <literal>propertyMaker.getShorthand(PropertyList |
| propertyList)</literal> <itemizedlist spacing="compact"> |
| <listitem> |
| <para>if |
| <literal>(maker.shorthands)</literal> then for each shorthand |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>propertyList.getExplicit(int |
| shorthand.propId)</literal>; a shorthand must be |
| <literal>ListProperty</literal></para> |
| </listitem> |
| <listitem> |
| <para>if <literal>(not |
| null)</literal> parse the shorthand property value, |
| <literal>parser.getValueForProperty(propId, listprop, propertyMaker, |
| this, propertyList)</literal>; here <literal>propId</literal> is the |
| <literal>propId</literal> of this property, not of the shorthand; a |
| shorthand may contain values for several properties, and this method |
| retrieves the value for the current property; if <literal>(not |
| null)</literal> return it</para> |
| </listitem> |
| </itemizedlist>Note: the first |
| shorthand property maker in <literal>maker.shorthands</literal> that |
| returns a good property is used</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>if <literal>(null && |
| bTryInherit)</literal> |
| <literal>propertyMaker.findProperty(parentPropertyList, |
| true)</literal>: the whole process is repeated on the parent, and |
| possibly its parents, up to the root node.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>if <literal>(null && bTryDefault)</literal> |
| <literal>propertyMaker.make(PropertyList propertyList)</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>if there is a cached value, |
| <literal>defaultProperty</literal>, return it</para> |
| </listitem> |
| <listitem> |
| <para><literal>propertyMaker.make(PropertyList |
| propertyList, String value, FObj fo)</literal>; |
| <literal>value</literal> is the default value stored in the property |
| maker, <literal>fo</literal> is the parent FO <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>if default value is |
| <literal>inherit</literal>, |
| propertyList.getFromParent(<literal>propId</literal>) |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>if |
| <literal>(parentPropertyList != null)</literal> |
| <literal>parentPropertyList.get(propId)</literal>; the whole process |
| is repeated on the parent, and possibly its parents, up to the root |
| node.</para> |
| </listitem> |
| <listitem> |
| <para><literal>propertyMaker.make(PropertyList |
| propertyList)</literal>; this seems to create an endless recursion; |
| <literal>parentPropertyList == null</literal> in the root node.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>else check enumerated values |
| <literal>propertyMaker.checkEnumValues(value)</literal>: get the |
| enumerated property from <literal>propertyMaker.enums</literal></para> |
| </listitem> |
| <listitem> |
| <para>if <literal>(null)</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>propertyMaker.checkValueKeywords(String |
| value)</literal>; check if the value is a keyword in |
| <literal>propertyMaker.keywords</literal>; if so, substitute the value |
| with the value for which the keyword stands</para> |
| </listitem> |
| <listitem> |
| <para>parse the value <literal>p = |
| PropertyParser.parse(pvalue, new PropertyInfo(propertyMaker, |
| propertyList, fo))</literal></para> |
| </listitem> |
| <listitem> |
| <para>convert the property |
| <literal>propertyMaker.convertProperty(p, propertyList, |
| fo)</literal></para> |
| </listitem> |
| <listitem> |
| <para>if <literal>(null)</literal> |
| throw <literal>org.apache.fop.fo.expr.PropertyException</literal>, |
| which immediately is catched and rethrown as |
| <literal>FOPException</literal> (why?)</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>catch <literal>FOPException</literal>; this |
| means that this method may return a <literal>null</literal> |
| property</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>catch <literal>FOPException</literal>; this means that |
| this method may return a <literal>null</literal> property</para> |
| </listitem> |
| </itemizedlist></para> |
| |
| <para>The call stack at the <literal>findProperty</literal> and |
| <literal>make</literal>calls is: |
| <screen> |
| [1] org.apache.fop.fo.properties.PropertyMaker.findProperty (PropertyMaker.java:240) |
| [2] org.apache.fop.fo.properties.PropertyMaker.get (PropertyMaker.java:282) |
| [3] org.apache.fop.fo.PropertyList.get (PropertyList.java:252) |
| [4] org.apache.fop.fo.PropertyList.get (PropertyList.java:238) |
| [5] org.apache.fop.fo.FObj.getProperty (FObj.java:163) |
| [6] org.apache.fop.layoutmgr.PageLayoutManager.createPageAreas (PageLayoutManager.java:745) |
| </screen> |
| <screen> |
| [1] org.apache.fop.fo.properties.PropertyMaker.make (PropertyMaker.java:387) |
| [2] org.apache.fop.fo.properties.PropertyMaker.make (PropertyMaker.java:369) |
| [3] org.apache.fop.fo.properties.PropertyMaker.get (PropertyMaker.java:285) |
| [4] org.apache.fop.fo.PropertyList.get (PropertyList.java:252) |
| [5] org.apache.fop.fo.PropertyList.get (PropertyList.java:238) |
| [6] org.apache.fop.fo.FObj.getProperty (FObj.java:163) |
| [7] org.apache.fop.layoutmgr.PageLayoutManager.createPageAreas (PageLayoutManager.java:745) |
| </screen> |
| For properties whose maker is compound property maker: |
| <screen> |
| [1] org.apache.fop.fo.properties.PropertyMaker.findProperty (PropertyMaker.java:240) |
| [2] org.apache.fop.fo.properties.PropertyMaker.get (PropertyMaker.java:282) |
| [3] org.apache.fop.fo.properties.CompoundPropertyMaker.get (CompoundPropertyMaker.java:146) |
| [4] org.apache.fop.fo.PropertyList.get (PropertyList.java:252) |
| [5] org.apache.fop.fo.PropertyList.get (PropertyList.java:238) |
| [6] org.apache.fop.fo.flow.Leader.getLength (Leader.java:135) |
| [7] org.apache.fop.layoutmgr.AddLMVisitor.getLeaderAllocIPD (AddLMVisitor.java:305) |
| [8] org.apache.fop.layoutmgr.AddLMVisitor$2.getAllocationIPD (AddLMVisitor.java:290) |
| [9] org.apache.fop.layoutmgr.LeafNodeLayoutManager.getNextBreakPoss (LeafNodeLayoutManager.java:143) |
| </screen></para> |
| |
| </section> |
| |
| <section> |
| <title>Examples: Retrieving border and padding values</title> |
| |
| <para>In this section we follow in detail how the border and padding |
| values for the body region are retrieved. The relevant part of the |
| input FO file is: |
| |
| <screen> |
| <![CDATA[<fo:simple-page-master master-name="simpleA4" margin="4pt"> |
| <fo:region-body margin="4pt+20%" border="3pt solid black" |
| border-before-width="2pt" border-right-width="4pt" |
| border-start-width="inherit"/> |
| </fo:simple-page-master>]]> |
| </screen> |
| </para> |
| |
| <para>This section was written after I added the cache to the |
| look-up of property values.</para> |
| |
| <section> |
| |
| <title>Retrieving the <literal>margin-top</literal> value on |
| <literal>region-body</literal></title> |
| |
| <para>This what we are retrieving: |
| |
| <screen> |
| propertyList.getFOName() = "fo:region-body" |
| org.apache.fop.fo.FOPropertyMapping.getPropertyName(propId) = "margin-top" |
| </screen> |
| |
| The margin values are retrieved by the method |
| <literal>PropertyManager.getMarginProps</literal>. This is the call |
| stack that leads up to it and on to the retrieval of the value of |
| <literal>margin-top</literal>: |
| |
| <screen> |
| [1] org.apache.fop.fo.properties.PropertyMaker.findProperty (PropertyMaker.java:240) |
| [2] org.apache.fop.fo.PropertyList.findProperty (PropertyList.java:289) |
| [3] org.apache.fop.fo.properties.PropertyMaker.get (PropertyMaker.java:291) |
| [4] org.apache.fop.fo.PropertyList.get (PropertyList.java:261) |
| [5] org.apache.fop.fo.PropertyList.get (PropertyList.java:247) |
| [6] org.apache.fop.fo.PropertyManager.getMarginProps (PropertyManager.java:264) |
| [7] org.apache.fop.fo.pagination.RegionBody.getViewportRectangle (RegionBody.java:58) |
| [8] org.apache.fop.layoutmgr.PageLayoutManager.makeRegionViewport (PageLayoutManager.java:811) |
| [9] org.apache.fop.layoutmgr.PageLayoutManager.createPageAreas (PageLayoutManager.java:784) |
| [10] org.apache.fop.layoutmgr.PageLayoutManager.createPage (PageLayoutManager.java:721) |
| [11] org.apache.fop.layoutmgr.PageLayoutManager.makeNewPage (PageLayoutManager.java:441) |
| [12] org.apache.fop.layoutmgr.PageLayoutManager.doLayout (PageLayoutManager.java:191) |
| </screen> |
| </para> |
| |
| <para>The retrieval proceeds as follows: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>PropertyList.findProperty</literal>: Is the value in |
| the cache? No.</para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: |
| <literal>corresponding != null</literal>? No.</para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: Is this property |
| explicitly specified? No.</para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: Can the |
| corresponding property be computed? No, there is no corresponding |
| property.</para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: Is a shorthand |
| property for this property specified? Yes, <literal>margin</literal> |
| is a shorthand for it. The property value is retrieved as: |
| <screen> |
| listprop = "[(4000mpt +20.0%)]" |
| </screen> |
| It is a list property as are all shorthand properties. The |
| value for <literal>margin-top</literal> is extracted from it as: |
| <screen> |
| p = "(4000mpt +20.0%)" |
| </screen> |
| </para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyList.findProperty</literal>: Add the value to |
| the cache.</para> |
| </listitem> |
| </itemizedlist> |
| </para> |
| </section> |
| |
| <section> |
| <title>Retrieving the <literal>border-before-style</literal> |
| value on <literal>region-body</literal></title> |
| |
| <para>This what we are retrieving: |
| |
| <screen> |
| propertyList.getFOName() = "fo:region-body" |
| org.apache.fop.fo.FOPropertyMapping.getPropertyName(propId) = "border-before-style" |
| </screen> |
| |
| The border values are retrieved by the method |
| <literal>PropertyManager.getBorderAndPadding</literal>. This is the call |
| stack that leads up to it and on to the retrieval of the value of |
| <literal>border-before-style</literal>: |
| |
| <screen> |
| [1] org.apache.fop.fo.properties.PropertyMaker.findProperty (PropertyMaker.java:240) |
| [2] org.apache.fop.fo.PropertyList.findProperty (PropertyList.java:289) |
| [3] org.apache.fop.fo.properties.PropertyMaker.get (PropertyMaker.java:291) |
| [4] org.apache.fop.fo.PropertyList.get (PropertyList.java:261) |
| [5] org.apache.fop.fo.PropertyList.get (PropertyList.java:247) |
| [6] org.apache.fop.fo.PropertyManager.initBorderInfo (PropertyManager.java:155) |
| [7] org.apache.fop.fo.PropertyManager.getBorderAndPadding (PropertyManager.java:143) |
| [8] org.apache.fop.fo.PropertyManager.getMarginProps (PropertyManager.java:289) |
| [9] org.apache.fop.fo.pagination.RegionBody.getViewportRectangle (RegionBody.java:58) |
| [10] org.apache.fop.layoutmgr.PageLayoutManager.makeRegionViewport (PageLayoutManager.java:811) |
| [11] org.apache.fop.layoutmgr.PageLayoutManager.createPageAreas (PageLayoutManager.java:784) |
| [12] org.apache.fop.layoutmgr.PageLayoutManager.createPage (PageLayoutManager.java:721) |
| [13] org.apache.fop.layoutmgr.PageLayoutManager.makeNewPage (PageLayoutManager.java:441) |
| [14] org.apache.fop.layoutmgr.PageLayoutManager.doLayout (PageLayoutManager.java:191) |
| </screen> |
| </para> |
| |
| <para>The retrieval proceeds as follows: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>PropertyList.findProperty</literal>: Is the value in |
| the cache? No.</para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: |
| <literal>corresponding != null</literal>, but |
| <literal>corresponding.isCorrespondingForced()</literal> returns |
| <literal>false</literal>. The corresponding property is |
| <literal>border-top-style</literal>, which is not specified: |
| |
| <screen> |
| org.apache.fop.fo.FOPropertyMapping.getPropertyName(correspondingId) = "border-top-style" |
| </screen> |
| This is the corresponding property maker: |
| <screen> |
| this = { |
| baseMaker: instance of org.apache.fop.fo.properties.EnumProperty$Maker(id=816) |
| lr_tb: 54 |
| rl_tb: 54 |
| tb_rl: 43 |
| useParent: false |
| relative: true |
| } |
| </screen> |
| </para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: Is this property |
| explicitly specified? No.</para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: Can the |
| corresponding property be computed? Yes, it can be derived from the |
| property <literal>border</literal>, which is a shorthand for the |
| corresponding property <literal>border-top-style</literal>. The |
| returned value is <literal>87</literal>, which stands for |
| <literal>SOLID</literal>.</para> |
| <para>Note that the shorthand was not used in the |
| computation of |
| <literal>corresponding.isCorrespondingForced()</literal>, but it is in |
| the computation of the specified value of the corresponding |
| property.</para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyList.findProperty</literal>: Add the value to |
| the cache.</para> |
| </listitem> |
| </itemizedlist></para> |
| </section> |
| |
| <section> |
| <title>Retrieving the <literal>border-before-width</literal> |
| value on <literal>region-body</literal></title> |
| |
| <para>This what we are retrieving: |
| |
| <screen> |
| propertyList.getFOName() = "fo:region-body" |
| org.apache.fop.fo.FOPropertyMapping.getPropertyName(propId) = "border-before-width" |
| </screen> |
| |
| The border values are retrieved by the method |
| <literal>PropertyManager.getBorderAndPadding</literal>. This is the call |
| stack that leads up to it and on to the retrieval of the value of |
| <literal>border-before-width</literal>: |
| |
| <screen> |
| main[1] where |
| [1] org.apache.fop.fo.properties.PropertyMaker.findProperty (PropertyMaker.java:240) |
| [2] org.apache.fop.fo.PropertyList.findProperty (PropertyList.java:289) |
| [3] org.apache.fop.fo.properties.PropertyMaker.get (PropertyMaker.java:291) |
| [4] org.apache.fop.fo.properties.CompoundPropertyMaker.get (CompoundPropertyMaker.java:146) |
| [5] org.apache.fop.fo.PropertyList.get (PropertyList.java:261) |
| [6] org.apache.fop.fo.PropertyList.get (PropertyList.java:247) |
| [7] org.apache.fop.fo.PropertyManager.initBorderInfo (PropertyManager.java:157) |
| [8] org.apache.fop.fo.PropertyManager.getBorderAndPadding (PropertyManager.java:143) |
| [9] org.apache.fop.fo.PropertyManager.getMarginProps (PropertyManager.java:289) |
| [10] org.apache.fop.fo.pagination.RegionBody.getViewportRectangle (RegionBody.java:58) |
| [11] org.apache.fop.layoutmgr.PageLayoutManager.makeRegionViewport (PageLayoutManager.java:811) |
| [12] org.apache.fop.layoutmgr.PageLayoutManager.createPageAreas (PageLayoutManager.java:784) |
| [13] org.apache.fop.layoutmgr.PageLayoutManager.createPage (PageLayoutManager.java:721) |
| [14] org.apache.fop.layoutmgr.PageLayoutManager.makeNewPage (PageLayoutManager.java:441) |
| [15] org.apache.fop.layoutmgr.PageLayoutManager.doLayout (PageLayoutManager.java:191) |
| </screen> |
| |
| The difference with the call stack for |
| <literal>border-before-style</literal> is that |
| <literal>border-before-width</literal> is a compound property, with |
| a <literal>minimum</literal>, an <literal>optimum</literal> and a |
| <literal>maximum</literal> value. |
| </para> |
| |
| <para>The retrieval proceeds as follows: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>PropertyList.findProperty</literal>: Is the value in |
| the cache? No.</para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: |
| <literal>corresponding != null</literal>, but |
| <literal>corresponding.isCorrespondingForced()</literal> returns |
| <literal>false</literal>. The corresponding property is |
| <literal>border-top-width</literal>, which is not specified: |
| |
| <screen> |
| org.apache.fop.fo.FOPropertyMapping.getPropertyName(correspondingId) = "border-top-width" |
| </screen> |
| </para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: Is |
| this property explicitly specified? Yes. The property value is |
| retrieved as: |
| <screen> |
| p = "CondLength[2000mpt]" |
| </screen> |
| The specified value was <literal>2pt</literal>. When this attribute |
| value was added to the property list, it was converted to a |
| <literal>CondLength</literal> type. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para><literal>PropertyList.findProperty</literal>: Add the value to |
| the cache.</para> |
| </listitem> |
| </itemizedlist> |
| </para> |
| </section> |
| |
| <section> |
| <title>Retrieving the <literal>border-end-width</literal> |
| value on <literal>region-body</literal></title> |
| |
| <para>This what we are retrieving: |
| |
| <screen> |
| propertyList.getFOName() = "fo:region-body" |
| org.apache.fop.fo.FOPropertyMapping.getPropertyName(propId) = "border-end-width" |
| </screen> |
| |
| The border values are retrieved by the method |
| <literal>PropertyManager.getBorderAndPadding</literal>. The call stack |
| that leads up to it and on to the retrieval of the value of |
| <literal>border-end-width</literal> is identical to the call stack for |
| <literal>border-before-width</literal>. |
| </para> |
| |
| <para>The retrieval proceeds as follows: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>PropertyList.findProperty</literal>: Is the value in |
| the cache? No.</para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: |
| <literal>corresponding != null</literal>, and |
| <literal>corresponding.isCorrespondingForced()</literal> returns |
| <literal>true</literal>. The corresponding property is |
| <literal>border-right-width</literal>, which is explicitly specified: |
| |
| <screen> |
| org.apache.fop.fo.FOPropertyMapping.getPropertyName(correspondingId) = "border-right-width" |
| </screen> |
| </para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyMaker.findProperty</literal>: Compute the |
| corresponding property value. It is retrieved as: |
| <screen> |
| p = "CondLength[discard, 4000mpt]" |
| </screen> |
| The specified value was <literal>4pt</literal>. When this attribute |
| value was added to the property list, it was converted to a |
| <literal>CondLength</literal> type.</para> |
| </listitem> |
| <listitem> |
| <para><literal>PropertyList.findProperty</literal>: Add the value to |
| the cache.</para> |
| </listitem> |
| </itemizedlist> |
| </para> |
| </section> |
| |
| </section> |
| |
| </section> |
| |
| <!-- |
| The implementation before bug 26778: Properties leader-length |
| |
| leader-length.maximum="30%" |
| leader-length.minimum="20%" |
| leader-length.optimum="25%" |
| |
| basePropertyName = "leader-length" |
| subPropertyName = "maximum" |
| propId = 124 |
| subpropId = 2560 |
| |
| main[1] where |
| [1] org.apache.fop.fo.flow.Leader.getLength (Leader.java:167) |
| [2] org.apache.fop.layoutmgr.AddLMVisitor.getLeaderAllocIPD (AddLMVisitor.java:361) |
| [3] org.apache.fop.layoutmgr.AddLMVisitor$2.getAllocationIPD (AddLMVisitor.java:342) |
| [4] org.apache.fop.layoutmgr.LeafNodeLayoutManager.getNextBreakPoss (LeafNodeLayoutManager.java:166) |
| [5] org.apache.fop.layoutmgr.LineLayoutManager.getNextBreakPoss (LineLayoutManager.java:215) |
| [6] org.apache.fop.layoutmgr.BlockLayoutManager.getNextBreakPoss (BlockLayoutManager.java:240) |
| [7] org.apache.fop.layoutmgr.FlowLayoutManager.getNextBreakPoss (FlowLayoutManager.java:111) |
| [8] org.apache.fop.layoutmgr.PageLayoutManager.getNextBreakPoss (PageLayoutManager.java:261) |
| [9] org.apache.fop.layoutmgr.PageLayoutManager.doLayout (PageLayoutManager.java:226) |
| |
| propId = Constants.PR_LEADER_LENGTH | Constants.CP_MAXIMUM |
| = 2684 = 124 + 2560 |
| |
| In this older implementation the base value is obtained from the |
| layout context and propagated to the calculation: |
| |
| LeafNodeLayoutManager.getNextBreakPoss: |
| ipd = getAllocationIPD(context.getRefIPD()); |
| AddLMVisitor.getLeaderAllocIPD: |
| node.getLength(Constants.PR_LEADER_LENGTH | Constants.CP_MAXIMUM, ipd); |
| Leader.getLength: |
| length = (int)(((PercentLength) maxlength).value() * dim); |
| |
| This is wrong because it does not find out at which node the property |
| is specified and from which node the base length should be |
| obtained. In the new implementation LengthBase contains this |
| information as member parentFO: |
| main[1] dump maxlength |
| maxlength = { |
| factor: 0.3 |
| lbase: instance of org.apache.fop.datatypes.LengthBase(id=773) |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| main[1] dump maxlength.lbase |
| maxlength.lbase = { |
| parentFO: instance of org.apache.fop.fo.flow.Block(id=776) |
| propertyList: instance of org.apache.fop.fo.PropertyList(id=777) |
| iBaseType: 3 |
| } |
| |
| Result: |
| ipd = "MinOptMax: min=67520; opt=84400; max=101280" |
| --> |
| |
| <section> |
| <title>Percent-based and mixed property values</title> |
| |
| <section> |
| <title>Overview</title> |
| |
| <para>Properties may have relative values, expressed as a |
| percentage. The value is relative to a trait of the layout. Therefore |
| relative values can only be evaluated when the layout is |
| created. The FO tree must store them as an expression.</para> |
| |
| <para>The FO spec specifies for each property that can have a |
| relative value, which trait is the basis for the evaluation of the |
| relative value. FOP maintains that information in the property maker, |
| in its member <literal>percentBase</literal>. This is set when the |
| maker is created, see <literal>FOPropertyMapping</literal>.</para> |
| |
| <para>When the maker creates a relative property value object, |
| it stores its own member <literal>percentBase</literal> in the |
| property as member <literal>iBaseType</literal>. In this way the |
| property value contains the information that is needed at layout time to |
| find the trait that is the basis for the calculation of the actual |
| value.</para> |
| |
| <para>The possible values of the member |
| <literal>percentBase</literal> are listed in class |
| <literal>LengthBase</literal>. Both the interface |
| <literal>PercentBase</literal> and the class |
| <literal>LengthBase</literal> define static constants which are used |
| as types. The difference is as follows (from an email by Finn Bock, |
| edited by me): The idea is that the <literal>PercentBase.XXX</literal> |
| types name the stored values and the <literal>LengthBase.XXX</literal> |
| types name the algorithms for looking up a base value. Most of the |
| time these map one-to-one to each other, but for some I imaged that |
| they would be different. For example, <literal>margin-top</literal> |
| should really use an algorithm like |
| <literal>BLOCK_IPD_OR_PAGEHEIGHT</literal>, which would look for |
| either <literal>PercentBase.BLOCK_IPD</literal> or |
| <literal>PercentBase.PAGE_HEIGHT</literal>, depending on the FO |
| element.</para> |
| |
| <para>A <literal>LengthBase</literal> object contains a |
| reference to a parent FO node and a reference to a property list. In |
| this manner the <literal>LengthBase</literal> value contains the |
| information that is needed at layout time to locate the FO node or |
| property list which contains the trait that is the basis for the |
| calculation of the actual value, irrespective of the FO node at which |
| the property is resolved.</para> |
| |
| <para>The method <literal>LengthBase.getBaselength</literal> |
| uses the base type, member <literal>iBaseType</literal>, to determine |
| relative to which layout trait the value should be resolved. If the |
| trait is a property value, it is retrieved from the property list, in |
| the usual manner. If it is a layout dimension, it is taken from the |
| parent FO.</para> |
| |
| <para>The interface <literal>Numeric</literal>, which is |
| implemented by all classes that can participate in numeric operations, |
| uses the notion of <literal>dimension</literal>, which denotes the |
| type of numeric: for integers <literal>dimension = 0</literal>, for |
| lengths <literal>dimension = 1</literal>.</para> |
| |
| <para>The constructor of |
| <literal>RelativeNumericProperty</literal> calculates the dimension of |
| the new property value object as a combination of the dimensions of |
| the operands, depending on the operation: |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>multiplication adds dimensions: 0+0=0, 0+1=1+0=1,</para> |
| </listitem> |
| <listitem> |
| <para>division subtracts dimensions: 0-0=0, 1-0=1, 1-1=0,</para> |
| </listitem> |
| <listitem> |
| <para>other (addition, subtraction) does not change the |
| dimensions</para> |
| </listitem> |
| </itemizedlist></para> |
| |
| <para>A <literal>RelativeProperty</literal> contains the |
| operation between the operands in its member |
| <literal>operation</literal>. It is an integer. Names for the possible |
| integer values are listed as static members of class |
| <literal>RelativeProperty</literal>.</para> |
| |
| <para>Relative and mixed property values are retrieved in the |
| usual manner. After retrieval they must be resolved against the |
| relevant layout traits. This happens in the method |
| <literal>getValue</literal> of <literal>Property</literal> and its |
| subclasses.</para> |
| |
| <para>A <literal>RelativeNumericProperty</literal> is resolved |
| as follows: <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>RelativeNumericProperty.getValue</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>RelativeNumericProperty.getNumericValue</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>RelativeNumericProperty.getResolved</literal>. |
| This evaluates the expression tree by recursion. The nodes in the tree |
| are <literal>RelativeNumericProperty</literal> objects. The leaf nodes |
| are <literal>FixedLength</literal> and |
| <literal>PercentLength</literal> objects. On each node |
| <literal>getNumericValue</literal> is called. <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para>The relative numeric property |
| values call <literal>getResolved</literal> again, which descends the |
| tree and calls <literal>getNumericValue</literal> on its child |
| nodes.</para> |
| </listitem> |
| <listitem> |
| <para>The fixed lengths return their |
| millipoints.</para> |
| </listitem> |
| <listitem> |
| <para>The percent lengths return |
| <literal>factor * lbase.getBaseLength()</literal> <itemizedlist |
| spacing="compact"> |
| <listitem> |
| <para><literal>factor</literal> is |
| a member of the percent length object.</para> |
| </listitem> |
| <listitem> |
| <para><literal>LengthBase.getBaselength</literal> |
| gets the base length from the parent FO <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>FObj.getLayoutDimension</literal>. |
| The value is retrieved from the <literal>Map |
| layoutDimension</literal>. If that does not contain the desired layout |
| dimension, then its parent is consulted, all the way up to |
| <literal>fo:root</literal>.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| |
| </section> |
| |
| <section> |
| <title>Parsing a mixed property value</title> |
| |
| <para>Example: <literal><fo:region-body |
| margin="4pt+20%"/></literal>, property being parsed: |
| <literal>margin="4pt+20%"</literal>, <literal>propId</literal> = |
| 134.</para> |
| |
| <para><literal>PropertyParser.parseProperty</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>next()</literal>, which scans the next token; |
| at its return: |
| <screen> |
| this = { |
| propInfo: instance of org.apache.fop.fo.expr.PropertyInfo(id=736) |
| org.apache.fop.fo.expr.PropertyTokenizer.currentToken: 12 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenValue: "4pt" |
| org.apache.fop.fo.expr.PropertyTokenizer.currentUnitLength: 2 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenStartIndex: 0 |
| org.apache.fop.fo.expr.PropertyTokenizer.expr: "4pt+20%" |
| org.apache.fop.fo.expr.PropertyTokenizer.exprIndex: 3 |
| org.apache.fop.fo.expr.PropertyTokenizer.exprLength: 7 |
| org.apache.fop.fo.expr.PropertyTokenizer.recognizeOperator: true |
| } |
| </screen> |
| i.e. the whole expression is a single token, it is of type |
| <literal>PropertyTokenizer.TOK_NUMERIC</literal> (= 12), the unit is |
| 2 chars long.</para> |
| </listitem> |
| <listitem> |
| <para>Loop forever. <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Analyse the expression. Start with |
| <literal>parseAdditiveExpr</literal> <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>parseMultiplicativeExpr</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>parseUnaryExpr</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>parsePrimaryExpr</literal>; |
| the unit may be a relative unit (em) which must be resolved against |
| the font size <itemizedlist spacing="compact"> |
| <listitem> |
| <para>construct a property |
| value object: |
| <screen> |
| prop = "4000mpt" |
| prop.getClass() = "class org.apache.fop.fo.properties.FixedLength" |
| </screen></para> |
| </listitem> |
| <listitem> |
| <para><literal>next()</literal>: |
| scan for the next token; |
| <screen> |
| this = { |
| propInfo: instance of org.apache.fop.fo.expr.PropertyInfo(id=736) |
| org.apache.fop.fo.expr.PropertyTokenizer.currentToken: 8 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenValue: null |
| org.apache.fop.fo.expr.PropertyTokenizer.currentUnitLength: 2 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenStartIndex: 3 |
| org.apache.fop.fo.expr.PropertyTokenizer.expr: "4pt+20%" |
| org.apache.fop.fo.expr.PropertyTokenizer.exprIndex: 4 |
| org.apache.fop.fo.expr.PropertyTokenizer.exprLength: 7 |
| org.apache.fop.fo.expr.PropertyTokenizer.recognizeOperator: false |
| } |
| </screen> |
| the next token is of type <literal>currentToken = |
| PropertyTokenizer.TOK_PLUS</literal>.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para><literal>next()</literal>: |
| scan for the next token; |
| <screen> |
| this = { |
| propInfo: instance of org.apache.fop.fo.expr.PropertyInfo(id=736) |
| org.apache.fop.fo.expr.PropertyTokenizer.currentToken: 14 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenValue: "20%" |
| org.apache.fop.fo.expr.PropertyTokenizer.currentUnitLength: 2 |
| org.apache.fop.fo.expr.PropertyTokenizer.currentTokenStartIndex: 4 |
| org.apache.fop.fo.expr.PropertyTokenizer.expr: "4pt+20%" |
| org.apache.fop.fo.expr.PropertyTokenizer.exprIndex: 7 |
| org.apache.fop.fo.expr.PropertyTokenizer.exprLength: 7 |
| org.apache.fop.fo.expr.PropertyTokenizer.recognizeOperator: true |
| } |
| </screen> |
| the next token is of type <literal>currentToken = |
| PropertyTokenizer.TOK_PERCENT</literal>. |
| The currentTokenValue <literal>20%</literal> is analysed:</para> |
| </listitem> |
| <listitem> |
| <para><literal>parseMultiplicativeExpr</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>parseUnaryExpr</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>parsePrimaryExpr</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>propInfo.getPercentBase</literal>: |
| create a PercentBase property |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>propInfo.getFunctionPercentBase</literal> |
| uses a stack of functions stkFunction, which currently <literal>== |
| null</literal></para> |
| </listitem> |
| <listitem> |
| <para><literal>if (null) |
| maker.getPercentBase(fo, plist)</literal>: create and return a |
| <literal>LengthBase</literal> property, which implements |
| <literal>PercentBase</literal> |
| <screen> |
| pcBase = "org.apache.fop.datatypes.LengthBase@171f189" |
| pcBase = { |
| parentFO: instance of org.apache.fop.fo.pagination.SimplePageMaster(id=786) |
| propertyList: instance of org.apache.fop.fo.PropertyList(id=807) |
| iBaseType: 5 |
| } |
| </screen> |
| the value of <literal>iBaseType</literal> is derived from |
| <literal>maker.percentBase == 5 == |
| LengthBase.BLOCK_WIDTH</literal>.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para><literal>pcBase.getDimension</literal>; |
| dimension: type of integer, int → 0, length → 1; used by |
| <literal>PercentBase</literal> and <literal>NumericProperty</literal>; |
| <literal>LengthBase</literal> has a dimension of 1</para> |
| </listitem> |
| <listitem> |
| <para>create a |
| <literal>PercentLength(pcval, pcBase)</literal>: |
| <screen> |
| prop = "20.0%" |
| prop = { |
| factor: 0.2 |
| lbase: instance of org.apache.fop.datatypes.LengthBase(id=751) |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| </screen> |
| <literal>factor</literal> comes from <literal>pcval</literal>, |
| <literal>lbase = pcBase</literal></para> |
| </listitem> |
| <listitem> |
| <para><literal>next()</literal>: |
| scan for the next token; the next token is of type |
| <literal>currentToken = PropertyTokenizer.TOK_EOF</literal>.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>return the <literal>LengthBase</literal> |
| property value object</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para><literal>evalAddition(NumericProperty op1, |
| NumericProperty op2)</literal>. <literal>op1</literal> and |
| <literal>op2</literal> are now <literal>Numeric</literal>, which is an |
| interface implemented by <literal>LengthProperty</literal>, of which |
| <literal>FixedLength</literal> and <literal>PercentLength</literal> |
| are subclasses: |
| <screen> |
| op1 = instance of org.apache.fop.fo.properties.FixedLength(id=744) |
| op2 = instance of org.apache.fop.fo.properties.PercentLength(id=757) |
| </screen> <itemizedlist spacing="compact"> |
| <listitem> |
| <para><literal>NumericOp.addition</literal> |
| <itemizedlist spacing="compact"> |
| <listitem> |
| <para>Construct a new |
| <literal>RelativeNumericProperty</literal> by adding the two |
| properties: |
| <literal>RelativeNumericProperty(RelativeNumericProperty.ADDITION, |
| op1, op2)</literal></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| <listitem> |
| <para>If <literal>currentToken = |
| PropertyTokenizer.TOK_EOF</literal>, break the loop.</para> |
| </listitem> |
| </itemizedlist></para> |
| </listitem> |
| </itemizedlist> |
| return the <literal>RelativeNumericProperty</literal>: |
| <screen> |
| prop = "(4000mpt +20.0%)" |
| prop = { |
| operation: 1 |
| op1: instance of org.apache.fop.fo.properties.FixedLength(id=744) |
| op2: instance of org.apache.fop.fo.properties.PercentLength(id=757) |
| dimension: 1 |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| </screen> |
| The value 1 for the operation corresponds to |
| <literal>RelativeProperty.ADDITION</literal>. The value 1 for the |
| dimension indicates that this is a length. PropertyList: |
| <screen> |
| this = "{margin=[(4000mpt +20.0%)]}" |
| </screen></para> |
| </section> |
| |
| <section> |
| <title>Resolving a mixed property value</title> |
| |
| <para>Example: Resolving the value of the property |
| <literal>margin-left</literal> of the FO node |
| <literal>fo:region-body</literal>. This value was specified as |
| <literal><fo:region-body margin="4pt+20%"/></literal>. |
| <literal>margin</literal> is a shorthand property for |
| <literal>margin-left</literal>.</para> |
| |
| <para>The property list of <literal>fo:region-body</literal> reads: |
| <screen> |
| this = "{margin=[(4000mpt +20.0%)]}" |
| </screen> |
| The retrieved property value is a |
| <literal>RelativeNumericProperty</literal>: |
| <screen> |
| prop = "(4000mpt +20.0%)" |
| prop = { |
| operation: 1 |
| op1: instance of org.apache.fop.fo.properties.FixedLength(id=817) |
| op2: instance of org.apache.fop.fo.properties.PercentLength(id=818) |
| dimension: 1 |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| </screen> |
| The value 1 for the operation corresponds to |
| <literal>RelativeProperty.ADDITION</literal>. The value 1 for the |
| dimension indicates that this is a length. |
| <screen> |
| op2 = "20.0%" |
| op2 = { |
| factor: 0.2 |
| lbase: instance of org.apache.fop.datatypes.LengthBase(id=751) |
| org.apache.fop.fo.properties.Property.specVal: null |
| } |
| lbase = "org.apache.fop.datatypes.LengthBase@171f189" |
| lbase = { |
| parentFO: instance of org.apache.fop.fo.pagination.SimplePageMaster(id=786) |
| propertyList: instance of org.apache.fop.fo.PropertyList(id=807) |
| iBaseType: 5 |
| } |
| </screen> |
| </para> |
| |
| <para>The <literal>RelativeNumericProperty</literal> is resolved in |
| the method call |
| <screen> |
| props.marginLeft = |
| this.propertyList.get(PR_MARGIN_LEFT).getLength().getValue(); |
| </screen> |
| in <literal>PropertyManager.getMarginProps()</literal>. |
| <literal>getLength()</literal> is a sort of cast; it returns the |
| property value if it is a length. The <literal>getValue()</literal> |
| method invoked is |
| <literal>RelativeNumericProperty.getValue()</literal>. |
| This calls |
| <literal>RelativeNumericProperty.getNumericValue()</literal>, which |
| calls <literal>RelativeNumericProperty.getResolved()</literal>. This |
| invokes the operation on its two operands, |
| <literal>NumericOp.addition2</literal>, which invokes |
| <literal>getNumericValue()</literal> on each |
| operand. <literal>PercentLength.getNumericValue()</literal> calls |
| <literal>LengthBase.getBaseLength</literal> on its member |
| <literal>lbase</literal>.</para> |
| |
| <para>Due to its value <literal>iBaseType == 5 == |
| LengthBase.BLOCK_WIDTH</literal> this invokes |
| <literal>parentFO.getLayoutDimension(PercentBase.BLOCK_IPD).intValue()</literal> |
| on its parent FO. The simple page master FO node does not have any |
| layout dimensions, its member <literal>layoutDimension</literal> is |
| <literal>null</literal>. Therefore it consults its parent FO. This |
| goes all the way up to the root FO node.</para> |
| |
| <para>The root FO node does have the required layout dimensions, which |
| are the page dimensions. These have been set on it |
| by the <literal>PageLayoutManager</literal> when the page was created |
| in its |
| method <literal>createPageAreas</literal>: |
| <screen> |
| ((FObj) fobj.getParent()).setLayoutDimension(PercentBase.BLOCK_IPD,pageWidth) |
| ((FObj) fobj.getParent()).setLayoutDimension(PercentBase.BLOCK_BPD,pageHeight) |
| PercentBase.BLOCK_IPD = 2, PercentBase.BLOCK_BPD = 3 |
| </screen> |
| As a result: |
| <screen> |
| layoutDimension = "{2=576000, 3=792000}" |
| key = "2" |
| getName() = "fo:root" |
| </screen> |
| </para> |
| |
| <screen> |
| [1] org.apache.fop.fo.FObj.getLayoutDimension (FObj.java:241) |
| [2] org.apache.fop.datatypes.LengthBase.getBaseLength (LengthBase.java:120) |
| [3] org.apache.fop.fo.properties.PercentLength.getNumericValue (PercentLength.java:82) |
| [4] org.apache.fop.fo.expr.NumericOp.addition2 (NumericOp.java:52) |
| [5] org.apache.fop.fo.expr.RelativeNumericProperty.getResolved (RelativeNumericProperty.java:105) |
| [6] org.apache.fop.fo.expr.RelativeNumericProperty.getNumericValue (RelativeNumericProperty.java:132) |
| [7] org.apache.fop.fo.expr.RelativeNumericProperty.getValue (RelativeNumericProperty.java:170) |
| [8] org.apache.fop.fo.PropertyManager.getMarginProps (PropertyManager.java:267) |
| </screen> |
| |
| <para><literal>PercentLength.getNumericValue()</literal> returns the |
| page width, which is multiplied by the requested factor of 0.2, and |
| added to the value of the fixed length, 4000. The resulting value is |
| returned and used for the variable <literal>marginLeft</literal>: |
| |
| <screen> |
| value = 119200.0 |
| props.marginLeft = 119200 |
| </screen> |
| </para> |
| |
| </section> |
| |
| </section> |
| |
| </chapter> |
| |
| <!-- Local Variables: --> |
| <!-- current-language-environment: UTF-8 --> |
| <!-- coding: utf-8 --> |
| <!-- default-input-method: TeX --> |
| <!-- End: --> |