When we have
space-before.optimum="from-parent()"
first the setValue() function of foSpaceBefore property calls the
evaluateLength() function of the expression parser.
That function calls the lexical analyser (evaluate() function). The lexical analyser detects three tokens
Function "from-parent"
Operator '('
Operator ')'
That series of tokens has the signature
F()
where "F" stands for "function with 0 or 1 NCName argument".
This signature is recognized by the syntax analyzer, and the syntax analyzer tries to "reduce" it to an unique token.
First, knowing that it's the "from-parent" function, it knows to which FO it applies. Second, the context says that the property type is "space-before" and that the component subtype is "optimum". If an argument had been specified, the hash function would have determined to which property type and which (optional) component subtype the function applied.
That makes it possible to call
property->tokenizeValue(foProperty::optimum);
This tokenizeValue function returns a number token with:
value = optimum of the space-before for that object
(as a floating point number, in millimeters)
power of the unit length = 1
(it's a length)
The expression parser then realizes the expression has been completly parsed, and since it has been called with evaluateLength(), it converts it back to a length in micrometers stored into a long integer.
| <integer> | foNumberToken |
| <number> | foNumberToken |
| <length> | foNumberToken |
| <length-range> | foLengthRangeToken |
| <length-conditional> | foLengthConditionalToken |
| <length-bp-ip-direction> | foLengthBpdIpdToken |
| <space> | foSpaceToken |
| <keep> | foKeepToken |
| <angle> | foAngleToken |
| <color> | foColorToken |
| <shape> | foShapeToken |
| <character> | foCharacterToken |
| <string> | foStringToken |
| <family-name> | foStringToken |
| <name> | foNameToken |
| <country> | foNameToken |
| <language> | foNameToken |
| <script> | foNameToken |
| <id> | foNameToken |
| <idref> | (not used so far) |
| <uri-specification> | foUriSpecificationToken |
| <percentage> | if the percentage can be resolved inmediately: foNumberToken (number or length) if it cannot be resolved until layout: foExpression |
| <time> | (not used so far) |
| <frequency> | (not used so far) |
| (none) | foOperatorToken |
| (none) | foFunctionToken |
A percentage like
space-start="10%"
is with respect to the inline-progression-dimension of the
closest ancestor block-area.
It means that the expression handler to know _what_ to look for, to take a percentage of.
It is a good idea _not_ to precompute this value before calling the expression handler, because in case we would not need it, it would be lost processor time, so we should only compute it on demand.
We shall pass to the expression handler a code telling the formatting object how to compute "a hundred percent":
getIPDOfClosestAncestorBlockArea = 5
This code would be of enumerated type:
foExpression::getPercentage
Alternatively, we could use a pointer to the member function of
foFormattingObject that can give the meaning of "a hundred percent":
foFormattingObject::getIPDOfClosestAncestorBlockArea
When the percentage cannot be computed before layout time, the evaluation
is deferred, and the percentage is stored "as is" in a foExpression.
(Alternatively, we could use a char *).
This expression uses a foPercentageToken to represent the percentage. The expression is "as reduced as possible". For example,
2 * 3%
gets reduced to
6%
but we cannot reduce
2mm + 3%