I think this will be a good improvement to implement to the JavaFX
layout algorithm. I see that you filed JDK-8276671 [1] to track this
enhancement.
As noted, the main concern will be making sure we don't break existing
applications, so testing this will be key.
One other issue that will need to be addressed is what a good the
threshold would be for the maximum number of iterations, such that if it
doesn't converge we will stop anyway (and log a warning). This is a
trade-off between performance and accuracy, although as noted in the JBS
issue, if the layout doesn't converge it's a bug. The value we
ultimately choose can be discussed during the review and testing.
Regardless of what the threshold is, I recommend a system property
(named something like "com.sun.javafx.scene.layout.threshold"). This
will be helpful during testing.
What do other developers think? Would this be a useful problem to solve
in layout?
-- Kevin
[1] https://bugs.openjdk.java.net/browse/JDK-8276671
On 11/4/2021 7:31 PM, 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