A new layout algorithm for the Classic-Engine

When you’re afraid of touching your old code, it is a good time for a rewrite. The code that I was afraid most was burried deep inside the Layout-Controller.

The development of layout-engine of the Classic-Engine was purely driven by need with an almost obscene lack of planing. However, it worked surprising well – the engine was swift and fast. Even when the layout-manager implementation was almost already out of control (better dont touch it, but still working), we were able to get more performance out of it.

Stephane Grenier, founder and author of LandLordMax, was truly amazed about the performance gains we achieved in the last year. To quote his comment on his Blog

In regards to performance, as far as I understood the biggest gains were in upgrading to 0.8.7-10 I even posted a message to the forum about this. Based on the performance differences, and the fact that version 0.8 (based on information from their head developer) will eventually be able to print combined reports (which is great if you want to print multiple invoices directly within the invoice list) we definitely upgraded to the latest 0.8 version.

But in JFreeReport 0.8.8, the subreporting caused some major changes in the layouting system. If you add new features, you always pay a price for it.

Fixing this innocent little bug #1681595 is more difficult than expected. A quick and dirty fix would tear down the remaining architecture – at the end, we may have implemented a fix for one bug, but laid the fundament for a whole new series of bug. No! Heading down this path would have been stupid and a receipt for doom and desperation.

But: We already stole the subreport-implementation from the Flow-Engine. And once you’ve started stealing, you can’t stop halfways. LibLayout, the layouting system of that engine looks nice too ..

During the last week, I’ve downported and modified the rendering pipeline of LibLayout. The Classic-Engine has no need for CSS-StyleSheets and it does not (and cannot [for compatibility reasons]) make use of the DOM-oriented architecture of LibLayout. So all we need is the last stage of the rendering process: The part where abstract elements turn into content.

So far, the extracted renderer is working and produces reports with the new layouting system. With this layouter, a many of the most hated restrictions of the old engine will be history:

  • Bands can span multiple pages.
  • Text-Elements can produce formatted text. A single text element can use several different fonts and font-styles.
  • Text-Elements can contain inline-images.
  • Dynamic-Height Text-Elements will be considerable faster.
  • The layouter now has documented rules how the layout is computed.

For me, the last point is the most important one. It took me several days to understand how the old layouting system really works. It is easy, if all elements are static. But as soon as one element uses relative positioning (percentages instead of absolute values), things became very messy. With the new system in place, the report layout finally behaves deterministic.

But you alway pay a price ..

As the layouter now uses different principles to perform its job, the internal API massively changed. There old OutputTargets are almost gone – right now they are dummy classes to maintain some backward compatiblity. All of the old layouter implementation classes are gone and only a few will continue to exist as dummy or backward-compatibility classes.

There will be border-cases, where the new layouting engine does not exactly behave like the old one. Everyone who relied on the old behaviour, that bands will not span multiple pages, will now have to change the report definitions.

Functions which modify the page-footer or a repeating group-footer during the page-finished event will produce different results now. In the old days, such changes never changed the page-break position. Now, this can happen. If the page-footer grows, it may start to move the last band to the next page. However, it is still better not to change the footer-structure during this even.

Well, the fact, that – right now – this two-weeks old implementation is slower than the old one should surprise no one. Once we have the same insane amount of caching and heuristics in place, we shall come back to our old performance high.

One final word: Once this implementation is complete, the next release of the classic-engine will be called ‘JFreeReport-0.8.9’. One step closer to a ‘1.0’ version.

This entry was posted in Development, Performance on by .

About Thomas

After working as all-hands guy and lead developer on Pentaho Reporting for over an decade, I have learned a thing or two about report generation, layouting and general BI practices. I have witnessed the remarkable growth of Pentaho Reporting from a small niche product to a enterprise class Business Intelligence product. This blog documents my own perspective on Pentaho Reporting's development process and our our steps towards upcoming releases.