Looks like you made a thorough analysis. What I read made sense to me
although I didn't check everything to the last character. Providing
the Context interface through the LayoutContext didn't occur to me
and I don't know if it's the right way, but if it just clicks in
there without much hassle then it's probably a good idea. I'd have
implemented the Context as an inner class to the LMs but then I
haven't investigated this so thoroughly as you just did. I simply
stumbled over it back in January and what I wrote there was simply
what was occuring to me at the time (having been a newbie to the
layout engine, too, back then).
So. I believe you're on the right course. Your approach seems to be
fine-grained enough to handle every case and still limit the
additional code to where it is needed.
I have been working on this for the last couple of days and I am not so
sure any more about the 'being on the right course' bit. So this is a
bit of a cry for feedback. I will try to outline the issues.
Most percentages are being resolved in the same way: Find the
appropriate ancestor area and get the relevant dimension from it. That
sounds very simple. The current system solves this by a) using the fo
tree to navigate upwards until an appropriate fo is found which
generates the type of area we are looking for and b) by the layout
managers to attach dimension information to the fos. The reason we are
looking for a redesign is that this doesn't appear to be the right way
to attach layout information to the fos. The current system is also not
complete in its implementation but that is a different issue.
The alternative proposed is to use a context which is created by the
layout managers and passed to the property resolution system, i.e. the
getValue() call. Sounds good so far as the layout managers have access
to the dimension information, actually in my code in the moment the
layout managers are the context, that is they implement the interface I
have defined for the context. But we still need to move up some form of
tree or list to find ancestors. The obvious choice would be the area
tree but that doesn't work as in many cases when we need a resolved
property value the areas (as objects in fop) haven't been created yet.
Also the areas are not linked back upwards in the tree although a
parent pointer could be introduced for that purpose. So, if we can't
use the area tree and don't want to use the fo tree what then? The next
thing coming to mind is the layout managers as they form a tree
structure as well. They even have a parent pointer. So, to find the
dimensions we are looking for we navigate up the parent links of the
layout managers until we find one which generates what we are looking
for and get the dimensions from it.
That is a very good summary of the issue. Thank you.
But, the parent link is not set
consistently and sometimes late. There is for example the case where a
layout manager in its constructor accesses a property value. To be able
to resolve it would need to know its parent layout manager which isn't
set yet. The fix for that is to carry the parent layout manager into
all layout manager constructors.
Or delay all calls to Length.getValue(..) until after the layout manager
tree is completed and the dimensions are available. So the
initialization is allowed to store Lengths but only during
getNextKnuthElement() is it allowed to extract the int values from the
This is where my problem is. We have a system now which is simple
(attach dimension information to the fo tree) and we are replacing it
with something that changes many internal interfaces, virtually
hundreds of method calls by adding extra parameters, and still does the
Which is exactly why I didn't complete the work at the time.
Navigate up a tree structure (and I am not 100% sure that
navigating up the layout manager tree really is the right thing to do)
to find a suitable node and get the appropriate values from that node.
The information obviously belong in either the LM tree or in the Area
tree. So it is the right thing IMO to move it out of the fo tree.