[reportlab-users] Miscalculation when using keepWithNext

Robin Becker robin at reportlab.com
Thu Nov 4 06:47:35 EDT 2021

Hi Pierre,

I think you are probably right in your analysis.

1) It's probably a bug to skip things that are zero width and non-zero height, It would be helpful to know what kind of 
flowable was involved there.

2) As you say it would be better to overestimate the required height, but best would be to compute correctly, but that 
requires us to check for inclusion in a frame and to work out what the extra height requirement is. Actually we can find 
out when we have a frame above us and inspect  whether we are at the top of a frame and what if it would do at this 
point if we get added.

The overall algorithm is badly designed, but it's probably far too late to adopt a better one.

On 04/11/2021 07:22, Pierre Ossman wrote:
> Hi,
> We've run in to an issue with ReportLab where it can orphan a heading under some circumstances, despite things being 
> correctly marked with keepWithNext.
> After some digging we found that flowables._listWrapOn() does not compute the same height as Frame._add(). So what 
> happens is that KeepTogether things the flowables will all fit, but once the Frame starts adding things the last element 
> gets punted to the next page.
> I'm afraid I don't have an easy example for you, but I do have some numbers that should allow anyone to go through the 
> code.
> We have the following elements that are all marked keepWithNext:
> Width   Height   Space Before    Space After
> --------------------------------------------
> 0       3        0               0
> 470     15       12              6
> 470     36       6               0
> The frame is at y=67. The space required for the above elements is 3+12+15+6+36=72. I.e. it won't fit. However 
> _listWrapOn() computes a required height of 57 here, so it thinks things will fit.
> There are two bugs in play here:
> a) _listWrapOn() ignores things with 0 width, however Frame._add() does not. So the first element gets discarded, 
> dropping 3 from the resulting height.
> b) _listWrapOn() assumes it is at the top of a frame, and should therefore discard the first flowable's spaceBefore. 
> This seems unsafe as it will then often underestimate the space required. It would likely be better to assume it is 
> never at the top and hence overestimate. This bug then acts on the second flowable (since the first was dropped), 
> dropping another 12 from the total height.
> And 72 - 12 - 3 = 57, and we get the bogus height number.
> For now I've worked around this by making sure that initial flowable is 1×3 instead of 0×3.
> I also noticed that KeepTogether._H0 is probably incorrect since it doesn't include spaceBefore. But that might be tied 
> to the assumption of always being at the top of a frame.
> Regards

Robin Becker

More information about the reportlab-users mailing list