Skip to content

Conversation

hjohn
Copy link
Collaborator

@hjohn hjohn commented Aug 17, 2025

This PR adds the necessary logic to automatically relayout unmanaged nodes when they're dirty as specified by the documentation. Relevant sections (emphasis mine):

Parent::requestLayout

If this parent is either a layout root or unmanaged, then it will be added directly to the scene's dirty layout list, otherwise requestParentLayout will be invoked.

Node::managedProperty

If a managed node's layoutBounds changes, it will automatically trigger relayout up the scene-graph to the nearest layout root

And:

If an unmanaged node is of type Parent, it will act as a "layout root"

From this I conclude that:

  • A layout root is any node that is unmanaged (and of type Parent), or a Scene's root node
  • Changes requiring layout in managed children that have an unmanaged parent somewhere in their ancestry should cause layout to be triggered for the affected areas
  • Automatic relayout is triggered either by scheduling a pulse (for scene roots) or by adding a layout root to the Scene's dirty layout list

Note that Scene currently does not have a dirty layout list.

Note also that the documentation for requestLayout probably meant to say "scene root or unmanaged" instead of "layout root or unmanaged."


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed (2 reviews required, with at least 1 Reviewer, 1 Author)

Issue

  • JDK-8365637: Unmanaged nodes are not added to the Scene's dirty layout list (Bug - P4)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1874/head:pull/1874
$ git checkout pull/1874

Update a local copy of the PR:
$ git checkout pull/1874
$ git pull https://git.openjdk.org/jfx.git pull/1874/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 1874

View PR using the GUI difftool:
$ git pr show -t 1874

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1874.diff

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Aug 17, 2025

👋 Welcome back jhendrikx! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Aug 17, 2025

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk openjdk bot changed the title JDK-8365637 Unmanaged nodes are not added to the Scene's dirty layout list 8365637: Unmanaged nodes are not added to the Scene's dirty layout list Aug 17, 2025
@openjdk openjdk bot added the rfr Ready for review label Aug 17, 2025
@hjohn
Copy link
Collaborator Author

hjohn commented Aug 17, 2025

There is a tiny change in the documentation, but it doesn't change the meaning (a scene root is a layout root, and unmanaged nodes are layout roots; there are no other types of layout roots). Can do a CSR though if deemed needed.

@mlbridge
Copy link

mlbridge bot commented Aug 17, 2025

Webrevs

@andy-goryachev-oracle
Copy link
Contributor

/reviewers 2

@openjdk
Copy link

openjdk bot commented Aug 18, 2025

@andy-goryachev-oracle
The total number of required reviews for this PR (including the jcheck configuration and the last /reviewers command) is now set to 2 (with at least 1 Reviewer, 1 Author).

@andy-goryachev-oracle
Copy link
Contributor

@hjohn would it be possible to add a unit test?

@andy-goryachev-oracle
Copy link
Contributor

There is a single word change in the javadoc. Do we need a CSR?

@nlisker
Copy link
Collaborator

nlisker commented Aug 18, 2025

There is a single word change in the javadoc. Do we need a CSR?

No. Even for larger doc fixes I never needed one.

@nlisker
Copy link
Collaborator

nlisker commented Aug 18, 2025

If the node is unmanaged, why does it need a relayout in practice?

@hjohn
Copy link
Collaborator Author

hjohn commented Aug 18, 2025

If the node is unmanaged, why does it need a relayout in practice?

The unmanaged node does not need relayout, but its potentially managed children do. Just like a Scene does not need layout, but its root does. A node being unmanaged affects its parent (the parent must skip it for layout calculations), but does not free it from doing layout on its own children (if I interpret the documentation correctly).

Let's take this hierarchy:

Region
     StackPane (unmanaged)
           ImageView

The Region will not lay out the stack pane as it is unmanaged, so I position the unmanaged child manually with resizeRelocate. The StackPane now has a defined position and size. When I add children to it, the StackPane's layout (and conversely layoutChildren) should still be called to ensure the children nicely fill the StackPane's space.

JavaFX currently will do steps 1 and 2, but does not do step 3:

  1. Another child is added to the StackPane (an overlay for the ImageView) this triggers a requestLayout on that child which marks it as needing layout
  2. This propagates to the parent, which is also marked as needing layout, but it is considered to be a layout root, so no further propagation occurs
  3. Since a layout root was encountered, it should be added to the list of dirty layout roots (implemented in this PR). This will clear all the needs layout flags (otherwise they stay true and never go back to false again).

The documentation however seems quite clear that step 3 is also supposed to be done.

@kevinrushforth
Copy link
Member

@arapte Can you review this?

@nlisker
Copy link
Collaborator

nlisker commented Aug 18, 2025

Does SubScene's root also count as a layout root?

@hjohn
Copy link
Collaborator Author

hjohn commented Aug 18, 2025

Does SubScene's root also count as a layout root?

After investigation, it seems that SubScene's are considered scene roots, so that would make it a layout root as well. This code in Parent (which monitors Scene/SubScene properties) convinces me that's the case:

    sceneRoot = (newSubScene != null && newSubScene.getRoot() == this) ||
                (newScene != null && newScene.getRoot() == this);
    layoutRoot = !isManaged() || sceneRoot;

@palexdev
Copy link

If the node is unmanaged, why does it need a relayout in practice?

The unmanaged node does not need relayout, but its potentially managed children do. Just like a Scene does not need layout, but its root does. A node being unmanaged affects its parent (the parent must skip it for layout calculations), but does not free it from doing layout on its own children (if I interpret the documentation correctly).

Let's take this hierarchy:

Region
     StackPane (unmanaged)
           ImageView

The Region will not lay out the stack pane as it is unmanaged, so I position the unmanaged child manually with resizeRelocate. The StackPane now has a defined position and size. When I add children to it, the StackPane's layout (and conversely layoutChildren) should still be called to ensure the children nicely fill the StackPane's space.

JavaFX currently will do steps 1 and 2, but does not do step 3:

1. Another child is added to the StackPane (an overlay for the ImageView) this triggers a requestLayout on that child which marks it as needing layout

2. This propagates to the parent, which is also marked as needing layout, but it is considered to be a layout root, so no further propagation occurs

3. Since a layout root was encountered, it should be added to the list of dirty layout roots (implemented in this PR).  This will clear all the needs layout flags (otherwise they stay `true` and never go back to `false` again).

The documentation however seems quite clear that step 3 is also supposed to be done.

So, as of now unmanaged parents do not layout their children? I thought they did.

immagine Am I getting something wrong?

@hjohn
Copy link
Collaborator Author

hjohn commented Aug 22, 2025

The documentation however seems quite clear that step 3 is also supposed to be done.

So, as of now unmanaged parents do not layout their children? I thought they did.

@palexdev You are right, I missed something... thanks for taking an extensive look.

My testing branch for this problem has a fix applied for JDK-8360940, but it now looks like that fix is incomplete.

What should happen when an unmanaged node is encountered is that changes in any of its children should not require re-layout of its parents (as an unmanaged node, all container parents ignore it and don't take it into account into their computations, so there is no point to re-layout the parents).

However, due to a bug, code in Node will always walk up the layout tree to the scene root and will mark all ancestors as needing layout. The code that does this is not very subtle and if a layout is in progress it can sometimes cause the layout flags to go into a bad state (this is what JDK-8360940 fixes). With that fix applied however, Node no longer always walks up the entire tree (and it shouldn't, as an unmanaged node is not affecting its parents). This however causes unmanaged parents to no longer be laid out at all, and this PR is supposed to fix that in turn.

So, what it looks like is that this PR and the fix for JDK-8360940 need to be a single PR.

Sorry for the bad PR, I will move this to draft and provide a complete fix.

@hjohn
Copy link
Collaborator Author

hjohn commented Aug 23, 2025

I've submitted PR #1879 to address the root cause of this issue. It is a much smaller change, but does expose a flaw in how layout flags are managed... see that PR for more details.

@hjohn
Copy link
Collaborator Author

hjohn commented Aug 23, 2025

This PR has become irrelevant, will close it for now.

@hjohn hjohn closed this Aug 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants