8360940: Layout stops updating when using Parent#setNeedsLayout(true) due to incorrect state management #1879
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Ensures proper propagation of layout flags when using
forceParentLayout = true
.This was the root cause of issue #1874
Note
Apparently it is still quite easy to mess up the layout flags. Basically, the layout flag tracked by Parent should always either be
CLEAN
for any scene graph branch, or!CLEAN
+ a layout pulse is scheduled on the correspondingScene
.However, with careful use of the public API
requestLayout
one can get these flags in a bad state still:Let's say I have a branch
A (root node under Scene) -> B -> C
, and a layout is in progress, and we're currently in thelayoutChildren
method ofC
. The flagperformingLayout
will betrue
for all nodes in the branchA
->B
->C
. Thelayout
method will set the layout flag toCLEAN
as its first action, so when we're atC::layoutChildren
, all flags have been reset toCLEAN
already. See theParent::layout
method for how all this works.Now, to mess up the flags, all you need to do is call
requestLayout
onB
orC
from thelayoutChildren
ofC
(or indirectly by changing something and something is listening to this and schedules a layout on something somewhere in this branch); note thatrequestLayout
is not documented to be illegal to call during layout, and some classes in FX will do so (ScrollPaneSkin, NumberAxis, etc..) risking the flags getting in a bad state... -- usually you get away with this, as there are many ways that layout is triggered, and eventually the flags will get overwritten and reset to a consistent state.The bad state occurs because this code path is followed (all code from
Parent
):Calls to
markDirtyLayout(false, false)
:Before going into the
else
(as none of the nodes is a layout root, andlocal
was set tofalse
) it will do setLayoutFlag(LayoutFlags.NEEDS_LAYOUT) -- this will set a flag on some node; to eventually end up in a consistent state, it must mark all ancestors as well and schedule a pulse (withToolkit.getToolkit().requestNextPulse()
)... but:Here there is a guard
!p.isPerformingLayout
, blocking propagation up the tree. As said, this flag istrue
for all nodes during a layout of the same branch. The end result thus is that some nodes have their layout flag changed toNEEDS_LAYOUT
, but it was not propagated, nor was a pulse scheduled...Progress
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1879/head:pull/1879
$ git checkout pull/1879
Update a local copy of the PR:
$ git checkout pull/1879
$ git pull https://git.openjdk.org/jfx.git pull/1879/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1879
View PR using the GUI difftool:
$ git pr show -t 1879
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1879.diff
Using Webrev
Link to Webrev Comment