Hi vincent,
thanks for your reply! Comments below.
Il giorno 05/set/08, alle ore 20:20, Vincent Hennebert ha scritto:
In LegalBreakHandler:
A lot of things here need changes... My (wrong) assumption was that
backtracking was needed only for best fit at line level and this
invalidate my backtracking implementation.
- what is the purpose of the countLayoutClass variable?
It's one of the ugly hack I was talking about ;) In best fit at line
level whenever a line ends only the best layout will be kept, so for
each layout class there can be only one layout: together with
classIter.hasNext(), countLayoutClass tell us if we are iterating the
unique layoutclass and so if we are going to remove the only layout
available. This is obviously no more valid for any other *fit algorithm.
- mind the second part of the ‘if (ratio < -1.0 || p.isForcedBreak())’
test: are you sure your modifications inside this if branch are meant
to apply to such a case?
What I do here is removing the layout if it's not the only available,
but as I wrote before this check is wrong.
- why are you removing the last element from the layout?
This is backtracking: in that case the line is overflowing the line
box, this layout should be removed but because this the only one we
remove the last element (so we are sure we don't overflow) and add it
to feasebleBreak: KnuthIterator will reconsider the removed element.
- the ‘removed’ boolean will be set to true as soon as one layout
overflows its containing part (l.78). But that doesn’t mean that,
inside the ‘if (best != null)’ branch, the best layout will be this
overflowing layout, does it? What if there is another feasible layout
that appears to have fewer demerits than the overflowing one?
Same story, it's the only layout in best fit at line level but, again,
it's a wrong assumption.
- plus, the demerits that will be computed for the overflowing layout
will correspond to the overflowing part (line/page); not to that part
after the last element has been removed. In that case the demerits
may
be completely different, possibly lower, or higher if the part
becomes
underfull.
... Ooops! My bad, I forgot to pass the modified layout to
computeDemerits.
In ParagraphLayoutManager:
- what do you mean by ‘paragraph best fit’ actually?
When the end of the paragraph is reached I keep only the best layout.
- I didn’t get the purpose of the oldMinPageNum and newMinPageNum
variables. I understand it’s to trigger the selection of the
best-fitting page, but why does the fact that those variables become
different mean that it’s time to proceed with the page selection?
I'm not sure this is correct, but that is my idea: I want to choose
the best layout for a page among all possible layouts for it.
Initially all layouts have 0 as page number, at some point one layout
will reach a page break and its page number will become 1: obviously
we don't know if this is the best layout. Until there's a layout
working on the first page we don't have all possible layouts for that
page and *MinPageNum is still 0; as soon as the last layout working on
page 0 reaches the page break, newMinPage become 1 and differs from
oldPageNum: we have all possible layout for page 1, I can choose the
best one. Actually I keep only the best of all layout when I reach
this point, but keeping all layout starting from the layout for the
first page would be a better solution. In other words, if I have two
possible layouts for the first page and the best of those have two
childs layout when I'm going choose the best page I should keep both.
- why did you implement page best-fit in this class? What happens for
a document solely made of blocks (or paragraphs of 1 line)?
Yes, I need to extend the implementation to other LMs.
From a higher level point of vue, my hope is to be able to do without
any backtracking, that would cost much processing time and memory. I
do
realize that this pretty much kills your whole approach :-\
Basically the algorithm would remain the same; only, steps would be
introduced at judicious places (!) where some layouts would be early
discarded. For first fit, as soon as a part is completed all of the
other layouts corresponding to the same part would be discarded. For
best fit, you keep one layout per layout class: in a call to next(),
you
compare each completed layout with the current layout of the same
class,
and you keep the best of them.
I suggest you not to bother about recovering right now, and make your
examples such that a final layout will be found in any case. The
recovering mechanism is a separate concern IMO (basically, the idea
will
be to keep an underfull layout under the hand, ‘just in case’).
It's not a problem, I agree, remember I was just coding as an exercise
to understand your code. In the past days I was already working on my
code to make backtracking independent from any *Fit algorithm and to
make backtracking working for page break too (think if you have two
layouts with same line breaking but one of them have just done a page
break and the other one not... bad things can happens if at line level
you keep the layout that will be discarded by the page breaker). It's
not wasted time, I've increased my understanding.
Just keep in mind my primary aim: rendering pages as soon as possible
to free memory. For this purpose I think a best fit at page level
algorithm it's mandatory. To allow nice layout the idea is to keep all
possible layouts for the last N pages starting from the best layout
for page N-1. For N=10, when laying out the page 11 consider only the
children layouts of the best page 1.
Getting tables working would allow me to validate the approach I
think,
since it’s one of the most complex typesetting objects. The next
step is
then to validate the design: for example working on tables made me
bring
major architectural changes. Implementing a few other features like
widows and orphans, keeps and breaks, maybe side-floats, would allow
me
to ensure the prototype has the right shape. The rationale being that
heavy refactoring is much easier on a prototype of a few thousand
lines,
rather than on a software of hundreds of thousand of lines...
Ok, thanks, for all your comments and suggestions. The next week I'll
meet Luca Furini and we will consider how to proceed. As soos as you
can share your code on tables handling I'll look in to it.
Dario