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.

Sec. 7.8.4 indicate that font-size percentages apply to the parent element's
font size, which would be from the FOTree, not from areas.

However, I fear that in the general case you may be right. The relative
column-width problem in tables may fall into this category. If so, then the
solution is to pass the relevant Area object to the "get" method so that it
can see more of the Area's context. Any Area can (or should) be able to see
not only its Area Tree ancestry, but its FOTree ancestry as well.

> >>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.

OK, what are the others?

> > 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.

OK. You may be right. See above.

> > 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.

That may be true for now, but I can see potential applications for anything
repetitious to be placed into a module of some sort that can be grafted into
non-static parts of the tree as well. I don't see any great need to make
this distinction.

> 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.

The FOTree equivalent would be to pass the Area to the "get" method, and let
the get method sort through the heritage of the Area to find the Areas/FObjs
that are needed to complete the computation.

> 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.

Am I getting closer by passing the Area to the "get" method?

> >  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.

Even XP has design. However, if the design isn't robust enough to work in
coding, then you have to revisit the design. That is what we are doing now.
So, with the benefit of your experience banging your head against these
issues, we can hopefully come up with a more robust design that works better
in coding. That too, may be subject to future revision. So it is good for
you to throw the hard cases up -- that is where we can see whether the
design is flexible enough to work in a general way. The design problem with
the *interface* side of this issue is not so much with program logic or data
structure, but with *knowing how to find* the data that we need. So I am
trying to suggest (or maybe find is the better word) an interface that lets
everybody see the things they need to see *within the context of the
FOTree*.

Also, one of the problems on implementation is that right now it affects not
just the FOTree but nearly all of the rest of FOP as well. If we can get the
interface issue resolved and then propogated to the rest of FOP, the
implementation design-code-test-design cycle become an order-of-magnitude
less expensive and less risky.

Your experience and insight on this issue are extremely important. If Areas
know how to find their FOTree heritage as well as their AreaTree heritage,
can you think of any concept that is missing to do Property resolution,
assuming that the relevant Area is passed to the "get" method on the FOTree
side?

Victor Mote

Reply via email to