Victor Mote wrote:
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
house.

2% of what? Of a reference area. Of what actually gets laid out on a page. If a single flow object gets laid out over more than one page, that reference may vary, but nothing changes in the FO Tree. It makes o sense to second-guess the Area tree within the FO tree. It's within the Area tree that all of these floe objects begin to take on concrete dimensions.


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.

Only one of the real issues, I'm afraid.


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
fop.fo.flow.RetrieveMarker 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:

  fo:marker
    fo:block
      fo:inline

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.

Not so. Grafting, OK. But you can't resolve the expressions without the areas.


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.

Yes, with the proviso that the grafting point is always within static-content. This is a real need, and I have concrete ideas on the implementation.


Thanks to pull-parsing, I have a stream of SAX-derived events available to me in a buffer when I encounter either fo:static-content or fo:marker. As a first pass, I can simple direct the streams into static-content or marker buffers. When the time comes to process the static content for a page, I simply merge the marker stream(s) into the static-content stream at the appropriate place, and process the resulting stream of node events as though seeing it for the first time.

In my perverse way, I call this "clean". But that only gets me an FO subtree. I still need to generate areas, and I still need to resolve percentage expressions in terms of the areas in that part of the Area tree which represents the static content. The precise way of managing this interaction between FO tree and Area tree is still vague for me.

 Hence, use the "get" interface when the information is
needed.

This is vague for me. My approach would be - do an implementation, then generalize, in the full knowledge of what is actually needed. What's been killing us is the implementation, or lack of it. It hasn't been implemented because no-one has yet been able to fully express what has to be implemented. We need to see the nitty-gritty of implementation as a solid foundation on which to build our generalizations. I suspect that Extreme Programming's startling insistence on design by coding (as I understand it) has a foundation in this kind of necessity. But then I don't know much about eXPr.


Peter
--
Peter B. West <http://www.powerup.com.au/~pbwest/resume.html>



Reply via email to