I've learned a few new things while working on the proposed new layout algorithm, and added a few new APIs:
1. A central concept of the new algorithm was the notion of a text-baseline node, indicated by Node::isTextBaseline(). I've come to realize that this property should percolate upwards in the scene graph: if a node has a text-baseline, the node's parent should also be considered to have a text-baseline. Adding this new behavior works surprisingly well and produces very intuitive layout results. 2. The default behavior of all layout containers is to pick the first text-baseline child to derive their own baseline offset. I've added Node::prefBaselineProperty(), which makes it possible to override this default selection: layout containers now pick the first child that reports Node::isPrefBaseline(), and only if there is no such child, they fall back to Node::isTextBaseline(). Developers can use this property to fine-tune their baseline layouts. 3. Optimization: Controls that contain text will often consist of a container of some sort and a javafx.scene.text.Text node within it. Computing the baseline offset of such a control is very easy with the new layout algorithm: public double getBaselineOffset() { return text.getLayoutBounds().getMinY() + text.getLayoutY() + text.getBaselineOffset(); } This works because changing text.layoutY will automatically schedule another layout pass for all of its parents. Re-layouting all parents is necessary because changing layoutY can change the effective baseline offset, and changing the baseline offset of any node can have layout implications on any of its parents. However, when we consider the Label control (which is probably among the most commonly used controls), this can be a bit excessive. Label controls are often used to display pure text, and as such, we can often "know" the baseline offset without actually needing to schedule a second layout pass. This assumption is only correct if the text within the Label is top-aligned (because if it isn't, the Label baseline offset can not be known in advance of an actual layout pass). To leverage this assumption, I've changed the default alignment for Label to TOP_LEFT (the default alignment of the base class Labeled is CENTER_LEFT). In most cases, there will be no visual difference anyway, because I imagine Label controls will seldomly be set to a minHeight or prefHeight. This specific scenario will enable an optimization where the first layout pass of Label will not schedule a second layout pass. It might be possible to find more such scenarios that can benefit from fast-path optimizations. 4. In order to get a better understanding of the layout process, I added additional logging to track layout passes. Then I compared the current algorithm with the new algorithm by tracking the initial layout after starting a sample program (i.e. all layout activity until the first frame is rendered). In the following log, "cumulative layout passes" means how often layoutChildren() has been invoked on any of the scene graph nodes. The actual log output includes a tree visualization of the entire scene graph that is being layouted, which I've removed for the sake or brevity. Current algorithm log output: INFO: Layouting VBox (triggered by scene out-of-pulse), cumulative layout passes: 49 INFO: Layouting VBox (triggered by scene pulse), cumulative layout passes: 43 INFO: Layouting VBox (triggered by scene pulse), cumulative layout passes: 0 New algorithm log output: INFO: Layouting VBox (triggered by scene out-of-pulse), cumulative layout passes: 86 INFO: Layouting VBox (triggered by scene pulse), cumulative layout passes: 19 A major difference is that the current algorithm will often leave the scene graph in a 'dirty' layout state after running a complete layout cycle, which necessitates another layout cycle as part of the next pulse. The new algorithm, however, leaves the scene graph in a clean layout state after a complete cycle, which takes more work at first, but saves work that would otherwise be done in the next pulse. 5. Since the new layout algorithm will leave the scene graph in a clean state, it is not necessary to repeatedly layout the same thing (like in Node::doLayoutPass()). Cases like these should be identified and may be changed to single layout invocations. Overall, I think there's good reason to assume that the proposed algorithm works and that it produces consistent results for application developers. At this point it would be useful to know whether or not to continue with the effort.