On Aug 2, 2007, at 12:13, Vincent Hennebert wrote:
Hi Vincent
Hope you still remember this one. Sorry about the late reply. Still
catching up on some missed posts during the holidays.
I’ve been thinking about the handling of keeps and breaks in tables
for
a while, and it seems to me that improvements could be done in that
whole area. I’ll use break-before as an example but what I’ll be
saying
applies to break-after and keeps as well.
While I've also been looking into that direction myself, I'm not sure
I agree with all of your suggestions (more inline below).
Currently, for every object to which the break-before property
applies,
the value of the property is checked at the beginning of the
getNextKnuthElements method and, if it corresponds to a hard-break,
a Knuth penalty with -inf value is produced. This has several
shortcomings:
- this leads to much code duplication;
- if, say, an fo:block has another fo:block as a child and both have
break-before, two penalties will be generated instead of one
(although
I’m suddenly not so sure of that, more later)
- this makes it difficult to improve breaks to distinguish columns
from
pages, and keeps to take integer values into account.
Very right about the above, and note that this is not only true for
block-level breaks and keeps (= page- or column-breaks), but also
inline-level, where at the moment, the situation is worse. keep-
together.within-line="always" only works for text-descendants of the
same FObj. Forcing a keep-with-previous on a graphic or an fo:inline
to have it always kept on the same line as the last line generated by
preceding PCDATA is currently impossible with FOP.
In fact, we don’t so much care about the penalty element itself as
whether there /should/ be a break between elements or not. I mean, the
LMs which actually care are those which concatenate the elements:
fo:flow, fo:block, fo:block-container, fo:table-cell, etc. And they
all
do it the same way:
iterate over the children LMs
for each LM:
if there is a following LM, then:
if the current LM has break-after or the following LM has
break-before, then
generate a Knuth forced break
So the main question is to know whether there is a break before a LM.
And here that’s quite simple, there are only a few shared behaviours:
indeed there is a break-before on an element if:
- the break-before property is set on the element itself or the
first of
its children:
fo:block, fo:block-container, fo:list-block
- it is set on the element itself or any of its children:
fo:table-row, fo:list-item
- it is set on the first of its children:
fo:table-caption, fo:table-cell, fo:list-item-body,
fo:list-item-label, fo:wrapper
- special:
- fo:table: on itself or first table-body
- fo:table-body: on the first fo:table-row child if any;
otherwise on
any of fo:table-cell children making the first row
- not applicable:
fo:table-column, fo:table-header/footer, fo:float, fo:footnote-body
I think I see another way of simplifying the necessary code in the
LMs, but I'm not a 100% sure...
Currently, a break is not propagated upwards or normalized in any way
in the fo-tree.
If you would have:
<fo:block>
<fo:block break-before="page">
<fo:block break-before="page">
Then we would get three nested Block instances, and the corresponding
BlockLM for the first outer Block always needs to check its first
childLM for the break-condition.
OTOH, the above is semantically equivalent to (I think we had already
established that there should not be a double page-break here)
<fo:block break-before="page">
<fo:block>
<fo:block>
If the LMs would be guaranteed to receive the 'normalized' form, the
break-condition can be tested for internally by the outer LM itself.
No need to look forward or back... The first descendants wouldn't
even need to check for breaks anymore.
So there would just be a couple of methods to write, for each
behaviour.
We could (for the moment) define a dedicated class with static
methods,
which would be called by each LM (some methods are imaginary, but you
get the idea):
<snip />
Interesting idea, too, but...
The benefit would be that the whole handling of breaks can be found in
just one place, instead of being spread among all the LMs. This is
easier to correct bugs; this is easier to implement new features
(column
vs page break, integer keeps...); this simplifies the
getNextKnuthElements methods of the LMs. And so on...
Agreed with the concerns, but I'm wondering if these portions of
code, instead of extracting them into a separate class, could be
centralized in, say, BlockStackingLM and InlineStackingLM...?
Cheers
Andreas