On Thu, 15 Jan 2026 18:32:39 GMT, Michael Strauß <[email protected]> wrote:
> > This is why IMHO any layout that relies on convergence is already broken;
> > it just happens to broken in a way that eventually leads to a stable
> > result...
>
> A single top-down layout pass only works when the layout constraints are
> acyclic. However, JavaFX expressly supports cyclic constraints, so the layout
> system can't chicken out. As soon as there's a cyclic dependency (parent
> layout is constrained by child, child layout is constrained by parent),
> you've got a fixed-point problem and need to solve it in some form, for
> example with multiple layout phases or iteration.
>
> Cyclic dependencies can appear in several situations:
>
> * CSS/layout coupling: styling influences sizing, sizing influences styling
> * Parent size depends on child size
> * Child wraps based on parent width
> * Baseline alignment
> * ...
Are you referring to media queries for the window size when you say that sizing
can influence styling? The others can be resolved similar to how `ScrollPane`
does this (see below).
> Looking at how other frameworks do this, we see that WPF and Android use two
> layout phases: a constraint-carrying measurement pass (given some available
> size constraint, how much space would each node like to have?), and a second
> arrange pass that authoritatively tells each node how much space it is given.
I would say that there's also two passes in FX, although less obvious. The
first pass is basically the calling of the compute methods. These cascade down
all the way down to the leaf level as each compute will call child compute
methods (but can use cached results) before any layout methods are called
(apart from the root one). I'm not sure what that pass should be called, but
it does sound a lot like what WPF is doing. Only after this does the layout
pass cascade down again via the layout calls.
This is why some layout problems can sometimes be solved by overriding a
compute method and doing some unorthodox work there (for which the correct
mechanism is to install a pre-layout listener).
> Such a system can break some cycles, especially the kind where parent and
> child sizes mutually constrain each other. It's not a catch-all solution;
> there can be higher-level cycles, for example with a scroll bar that, upon
> appearing, causes the layout to reflow, which then again influences the
> scroll bar.
`ScrollPane` handles that in one pass. Basically it computes the size of the
children, and if it determines there is need of a scroll bar, it does those
calculations again (which can result in the appearance of the 2nd scrollbar,
and the calculations are repeated one more time; this is quite visible in
`ScrollPaneSkin`). In effect, it solves this problem internally without
waiting for another layout pass, as compute methods can be called as often as
desired.
> Android detects relayout requests during the layout phase, and will allow for
> one additional round of measure+layout in the same frame; if a second
> relayout request is encountered, it is deferred to the next frame.
>
> In JavaFX, we don't have two phases of layout to break the easier cycles, and
> we don't have multiple rounds of layout. I think it is obvious that we need
> to do something about that, and pretending that cyclic constraints don't
> exist is not that.
>
> What I believe can work for JavaFX is a layout system that basically does
> this for each frame:
>
> ```java
> while (!layoutClean) {
> doCssPass();
> doLayoutPass();
> }
> ```
>
> If this doesn't settle in a very small number of iterations (something like
> 3), we can do the remainder of the work in subsequent frames to prevent
> unresponsive applications. Maybe we can even detect oscillations (e.g. scroll
> bar flip-flop) and suspend layout in these cases.
I think doing a loop of layout passes up to a limit is fine, although I'm not
sure if CSS needs to take part in that. One should not be changing styles
during layout, that's a pre-layout concern (which is before CSS runs) and not
something to do in the `compute` chain of methods nor the `layoutChildren`
methods.
Of course, JavaFX being very unrestrictive, one can easily fiddle with CSS
during layout calls, and create bad layouts, which hopefully converge, but at
some point there is **nothing** that can be done. As these problems tend to be
very visible, they're usually fixed quickly, unlike converging layouts which
escape notice. This is why I think we should warn when certain actions are
taken during layout. A layout that converges now, may stop converging when say
`modena.css` is updated or replaced.
-------------
PR Comment: https://git.openjdk.org/jfx/pull/1945#issuecomment-3756499809