Peter B. West wrote:

> > What about font-size="12pt+2%+0.8*from-parent(height div 32)" ?
> Good question.  Make it
> font-size="12pt+2%+0.8*(from-parent(height) div 32)" though.  Even
> nastier is
> font-size="12pt+2%+0.8*(from-nearest-specified(height) div 32)"
> because in markers and in static-content, we have to keep track of where
> *all* property specifications occur in the ancestry FO tree to resolve
> it.  In general, the functions will be resolvable as the FO tree is
> built.  The tree is "static", in the sense that the tree relationships

Correct. Neither of the examples given has anything to do with the interface
proposed, because all of the computations are done on the FOTree side of the

> are maintained in spite of any to-ing and fro-ing with the Area Tree.
> Markers are an exception, and because marker properties are resolved in
> the context of the static-content into which they are eventually placed,
> all the information required for from-nearest-specified() must be
> available in the static-content FO subtrees.

Yes, this is the real issue. Since an fo:marker's content can be used more
than one place, this requires that its contents be "grafted" into the tree
where needed.

I think the only trick here is to pass the static content context back to
the "get" method so that it knows how to get the information it needs. Sec
6.11.4 says that fo:retrieve-marker "is (conceptually) replaced by the
children of the fo:marker that it retrieves." The most general way that I
can think of to implement this is to force the passage of a parent in the "get" method's signature. This tells the
"get" method: "One of your ancestors is an fo:marker object, and, for
purposes of this "get", consider that ancestor grafted into the tree at this
fo:retrieve-marker's location." Of course, if there is no ancestor
fo:marker, pass a null.

Now, this raises another issue. FONode has a getParent() method. This method
may need to be expanded to include this concept. Any child could then ask
for its parent either with null (go up the tree through fo:marker, i.e. the
way the input specifies, and the way it works now), or with a "grafting
point" specified, so that if a grafting point is specified, it will go up
the tree in that direction instead. In fact, it may be good to create a
GraftingPoint interface that RetrieveMarker implements, in case there are
additional similar items now or in the future.

class Marker {
    getParent(GraftingPoint gp) {
        if (gp == null) {
            return this.parent;
        return gp.getParent(null);

So, lets use:
font-size="12pt+2%+0.8*(from-nearest-specified(height) div 32)
as an example. Lets assume an FOTree fragment that looks like this:


For both the block and the inline, the "get" will need to research its
ancestry to resolve the expression. If we pass the grafting point to the
"get", and the "get" directly or indirectly uses the getParent(GraftingPoint
gp) method to find that ancestry, it seems to me that everybody has
everything they need.

The key insight for me here is that *none* of this is actually dependent on
the Area Tree at all, that what we are really doing is grafting. I had
originally thought that some Area Tree information would need to be passed
in, but I really think the above is much more elegant, and more clearly
follows the concepts that are in play. Of cource, I rely on the rest of you
guys to tell me if I have missed something (a real possibility).

> Because this is not required in the fo:flows, a good deal of property
> storage efficiency is realizable.
> This is why I was talking some time ago about a PropertyValue type which
> is an RPN-style expression, which can be rapidly resolved without
> recourse to the general parser.  Without it, we have to carry at least
> some expressions around in the raw, after having first parsed them in
> order to determine that we can't resolve them, and then throw them to
> the parser again whenever a) we have sufficient context, or b) the page
> is re-laid.  The idea of performing a full parse on a given expression
> more than once makes me nauseous.

Again, this is an implementation detail, and doesn't affect the interface.
However, on the implementation side, it seems that the tradeoff will be
between doing a full parse each time, or creating lots of objects. John
Austin's inquiry about the huge number of objects created is what got me
started down this line of thinking. I suppose that the best way would be to
have your cake and eat it too -- store integers where possible, and create
objects where not possible, and teach everything how to tell the difference.
(Here is a half-baked idea that I don't want to even think about pursuing
for a while -- PropertyStrategy. With the API I have proposed, one could
conceivably store the Properties one of several ways, and have the user
select which one they want based on performance needs).

> The approach I am thinking about with such expressions is to associate
> the expression, and therefore the FO node, with the *area* which will
> provide the context for the resolution of the percentage component(s) of
> the expression.  (It may be enough to use the parent area of the areas
> that the node generates, and to work back to the appropriate reference
> area or other dimension when the parent dimensions are resolved.)

There are two issues: 1) getting the ancestry right, and 2) getting the
expression stored and resolved. In general, #1 goes with the interface, and
#2 goes with the implementation. ATM, I am less interested in the
implementation, except to make sure that it can be done. Do you think the
"grafting" idea works for issue #1?

> When the dimensions of such an area are resolved, the list of attached
> FO property expressions can also be resolved.  Exactly how to do this I
> am not yet sure, but I am thinking of something along the lines of a
> co-routine, implemented by message-passing queues, similar to the
> existing structure of the parser/FOtree-builder interaction.

Because a marker can be grafted into numerous places (retrieve-markers) in
the FOTree, the properties of its children can *never* be resolved. They
will always have to be computed on-the-fly, in real time, in the context of
the grafting point. Hence, use the "get" interface when the information is

Victor Mote

Reply via email to