phax / ph-pdf-layout

Java library for creating fluid page layouts with Apache PDFBox. Supporting multi-page tables, different page layouts etc.
Apache License 2.0
64 stars 11 forks source link

No splitting performed when nesting non-splittable within splittable PLVBox #28

Open hwanders opened 1 year ago

hwanders commented 1 year ago

Info: I'm using ph-pdf-layout 7.0.0.

When creating a splittable PLVBox and adding some large non-splittable PLVBoxes as rows, the calculations for vertical splitting seems to go wrong (or at least behaves in a way which I did not expect). This culminates in a debug message Cannot split because no vertical splittable elements are contained and an error of the form The value of 'StartTop' must be >= 0! The current value is: <negative number>.

By debugging I can see that the PLVBox elements do have too many rows (in m_aRows) which do not fit on the page such that fCurY becomes negative.

I guess, the problem lies in AbstractPLVBox.splitElementVert(...) which uses containsAnyVertSplittableElement() to determine whether splitting can be performed. My expectation is that splitting should be done if each contained row fits in the available height, even if those rows' contents are not splittable.

I have found that there is also a simple workaround for this: just wrap the inner (non-splittable) PLVBox with another splittable one which only contains that inner box.

This is a simple reproduction of the error, the workaround is added as comment in the loop:

public static void main(String[] args) throws Exception {
  var font = new FontSpec(PreloadFont.REGULAR, 10);
  var pageSet = new PLPageSet(new SizeSpec(100, 700));

  var list = new PLVBox(); // splittable
  pageSet.addElement(list);

  for (var i = 0; i < 3; i++) {
    var subList = new PLVBox().setVertSplittable(false); // non-splittable
    subList.addRow(new PLText("test", font).setExactHeight(700));
    list.addRow(subList); // workaround: list.addRow(new PLVBox(subList));
  }

  var pdf = new PageLayoutPDF().addPageSet(pageSet);
  // The following throws an "Internal error" with reason
  // "The value of 'StartTop' must be >= 0! The current value is: -700.0"
  pdf.renderTo(new ByteArrayOutputStream());
}
hwanders commented 1 year ago

To reformulate my expectation: I think if the PLVBox's rows are not vert-splittable themselves, it should consider the rows as whole elements and try to split those.

hwanders commented 1 year ago

I just played around a bit with the source code and just removing the block checking for vert-splittable elements did work in my case.

Probably the code is there for some reason, but after removing the code (and making the tests deterministic by using fixed date/time values and seeds for Random), all generated PDFs files remain exactly the same, so at least no existing tests are breaking. On the other hand, the block is never entered in any of the tests.

stale[bot] commented 11 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.