Hi Andreas, Andreas L Delmelle wrote: > 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.
Hope you still remember this one. Sorry about the late reply. Still catching up on some missed posts while I was not working on FOP :-] And thanks for your comments. <snip/> >> 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. I think I see your point. Basically you’re proposing a push method (a LM notifies its parent LM that it has a break-before) while mine is a pull method (a LM asks its children LMs if they have break-before). You’re more at the FO tree building stage, I’m more at the layout stage. In terms of efficiency I think both methods are equivalent as the same amount of method calls will be performed in either way. The push method might be slighty more complicated to implement in special cases like tables: when an fo:cell notifies its parent fo:table-body that it has a break-before, the table-body must figure out if the cell lies in the first row or not. A matter of taste, probably, but I think I’d prefer the pull method: the LM performs requests to the appropriate children LMs exactly when and if needed. That may simplify code as well (and improve its readability) as some form of pull method is necessary anyway (the mustKeepWithPrevious/WithNext/Together methods). I believe you already mentioned this idea of normalizing/simplifying the FO tree in the past. Note that it may exist in parallel as it addresses a different general issue. One concern I’d have is to make sure that a simplification leads to a semantically equivalent result. Given the complexity of the spec that might be difficult to establish. Not sure also if the overhead is compensated by the gain in the further processes (layout, area tree generation). But that’s a different topic. >> 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...? I thought of that, but a separate class looked cleaner to me for some reasons: - the LMs classes are already overcrowded with many different concerns - the code would be about the same for Block- and InlineStackingLM - we could factorize it into a common super-class but both those classes have subclasses to which breaks don’t apply (Flow-, StaticContentLM, for example). OTOH keeps apply to AbstractGraphicsLM which doesn’t inherit any of those classes. - a separate class allows to easily change/improve/replace the implementation - and, anyway, it’s obviously better like this... Vincent