Circling back to a new layout algorithm

John Hendrikx hjohn at xs4all.nl
Sat Nov 13 15:23:47 UTC 2021


I haven't taken a close look, but I've done some automated layout work 
before.  The baseline layout seems to be an interesting kind of problem 
where controls can influence each other, where normally they are mostly 
independent.

An iterative approach may be the only viable one, but it does leave me 
thinking if there isn't a better option. My primary concern is that it 
is relatively easy to construct a situation that would not converge quickly.

Given a fixed height control A with some text that is top aligned and 
which has a significant amount of padding at the bottom (maybe it has an 
image below the text), and another unbounded control B with its text 
vertically centered. Every time the algorithm tries to align the 
baselines of these two controls, the container grows a little bit 
bigger. This enlarges control B, pushing the baseline down (as it is 
centered), which in turn means that aligning control A on that new 
baseline will mean its bottom padding now extends beyond the containers 
size, and the container is enlarged again... Visually:

   +-------+ +-------+
   |   A   | |       |
   |       | |   B   |
   |       | |       |
   +-------+ +-------+

After 1 iteration:

             +-------+
   +-------+ |       |
   |   A   | |       |
   |       | |   B   |
   |       | |       |
   +-------+ +-------+

After 2 iterations:

             +-------+
             |       |
   +-------+ |       |
   |   A   | |   B   |
   |       | |       |
   |       | |       |
   +-------+ +-------+

In ASCII art this converges relatively fast, but it all depends on the 
size of control A and how large its bottom padding is.

I was wondering if this can be improved upon somehow.

--John

On 05/11/2021 03:31, Michael Strauß wrote:
> I previously proposed a new iterative layout algorithm [1] that
> supports baseline alignment and introduces new APIs to give developers
> control over the way nodes are aligned. This is a solution to the
> long-standing problem that JavaFX cannot reliably lay out nodes that
> are aligned on their baseline [2]. The new layout algorithm might also
> fix some issues where the scene graph layout only settles after
> interacting with the controls (for example, by clicking).
>
> I've created a small application that shows the new APIs and a
> correctly working baseline-aligned layout [3]. In addition to that, I
> also built SceneBuilder with both the old and new layout system, and
> played around with it to find out whether there were any regressions
> or visual differences. So far, I haven't found any.
>
> In order to move this forward, I think it would be a good idea to test
> the latest version of the new layout system in more real-world JavaFX
> applications. Any help from JavaFX application developers is greatly
> appreciated. It's as easy as checking out the JavaFX sources from the
> PR [1], building a local SDK and linking your application with the
> binaries.
>
>
> Finally, here's a high-level overview of the new algorithm:
>
> When Parent::layout() is called on a layout root (i.e. a scene root or
> an unmanaged node), it will lay out its children in a loop until the
> scene graph under the layout root is fully laid out, which means it is
> clean and doesn't require further layout. The totality of layout
> activity for a single layout root is called "layout cycle". A layout
> cycle will often take a few layout passes to finish (but not more than
> 2 in most cases). There is no limit on how often Parent::layout() will
> iterate to lay out its children, so in principle, this could lead to
> an infinite layout loop.
>
> One source of infinite layout loops are incorrectly implemented controls:
>
>     class PathologicalControl extends Region {
>         final Text text = new Text("foo");
>
>         PathologicalControl() {
>             getChildren().add(text);
>         }
>
>         @Override
>         protected void layoutChildren() {
>             text.relocate(0, text.getLayoutY() + 10);
>         }
>     }
>
> In this example, each call to layoutChildren() moves down the text
> node another 10 pixels from where it was, which causes the layout
> algorithm to schedule yet another layout pass. It's an infinite loop.
>
> The layout system detects this by tracking how often a node
> invalidates the scene graph in a single layout cycle. If a node
> exceeds a threshold of 100 invalidations, it will be suspended from
> layout and can no longer invalidate the scene graph in the current
> layout cycle. A warning will be logged to notify developers of that
> fact.
>
>
> [1] https://github.com/openjdk/jfx/pull/433
> [2] https://bugs.openjdk.java.net/browse/JDK-8090261
> [3] https://github.com/mstr2/jfx-layout-sample
>


More information about the openjfx-dev mailing list