On Tue, 28 Oct 2025 07:28:25 GMT, John Hendrikx <[email protected]> wrote:

> It is starting to look like there may be more code relying on double layouts 
> than I thought, even though most controls work absolutely fine. I think that 
> it is still worth pursuing eliminating the need for these (as you can 
> temporarily see the "wrong" positions), but it may take longer as each of 
> these will need an investigation.
> 
> I remain convinced though that the original fix in 
> https://bugs.openjdk.org/browse/JDK-8137252 was applied too hastily, and only 
> worked because it, unintentionally, simply always allowed double layouts.

That is very well possible, but it is what it is. I believe the main goal of 
the layout phase in a pulse is to make sure that "ultimately", all 
direct/indirect requests are handled. The secondary goal is that it should be 
done as efficient as possible, e.g. do not require 2 (or more) passes unless 
absolutely needed. 
The issue is, though, that there are a huge amount of possible scenarios, 
leading to situations that can not be dealt with by a single, optimized flow. I 
started documenting and analyzing scenarios, and even a very basic 2 node case 
poses issues that can go wrong.
Looking at it with our openjfx glasses, some of these scenarios are really bad. 
However, developers without internal knowledge often have no idea how and why 
it can go wrong. Adding bindings/listeners between siblings is a very common 
pattern, and when looking at my old code, I made tons of "mistakes" by having 
too much bindings that asked the layout phase to solve an almost impossible 
job. 
At least the layout system in JavaFX gives developers lots of freedom, and it 
promises to handle all edge cases. That fulfills the main goal (correct 
rendering, perhaps after a number of pulses, leading to flickering), but it 
makes the second goal (top-efficiency) really hard.

To make it harder (but very understandable), the layout phase spans a number of 
classes, where different concepts/choices are made (e.g. both Parent and Node 
have internal state that is used to determine whether to initiate a new pulse). 
That makes it really hard to come up with a system that would typically be used 
in these situations: use an algorithm that always works (although maybe less 
performant), and use optimizations in specific cases (e.g. no bindings in 
properties of children in a chontainer -> use this branch).

Something I've been thinking about every now and then is to introduce runtime 
warnings (ideally compiler *errors*, but that would require lots of upfront 
analysis), where the layout subsystem can warn that "a pretty complex situation 
occurred", e.g. when it is running into cyclic conditions that are not trivial 
to resolve without performance degradation. But that would be a major effort 
and conceptual change.

TLDR: I feel your pain and it can be very frustrating having to deal with 
non-optimal but valid code, deployed in the wild.

-------------

PR Comment: https://git.openjdk.org/jfx/pull/1945#issuecomment-3455150271

Reply via email to