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

Reply via email to