On Sat, 8 Aug 2026 18:59:06 GMT, Marius Hanl <[email protected]> wrote:
>> modules/javafx.graphics/src/main/java/javafx/scene/CssStyleHelper.java line
>> 104:
>>
>>> 102: Styleable parent = node;
>>> 103: int depth = 0;
>>> 104: while (parent != null) {
>>
>> there might be potential quadratic execution time here.
>>
>> imagine a long chain of nodes
>>
>> root
>> + node1
>> + node2
>> ...
>> + nodeN
>>
>>
>> - start by adding a child to nodeN, this makes the entire chain dirty.
>> - change style class in all the nodes in the chain
>> - add a second child to nodeN
>>
>> adding the second child recursively rebuilds every stale ancestor, walking
>> all the way to the root.
>
> this will only rebuild the style helper that needs it. And only the first
> ancestor. I can't see how this could be a problem - do you have a unit test
> in mind?
> I tested several scenarios and could not spot any problem. Note that this is
> a very rare case that usually only happens for the scenarios I implemented as
> tests
ok, so here is the test that passes in master and fails spectacularly with this
PR:
@Test
void checkQuadraticPerformace() {
scene.getStylesheets().add(toDataURL(
"""
.old {
-fx-padding: 1.0;
}
.new {
-fx-padding: 99.0;
}
"""));
AtomicInteger counter = new AtomicInteger();
class TPane extends Pane {
public TPane(String style) {
getStyleClass().add("style");
}
@Override
public Styleable getStyleableParent() {
counter.incrementAndGet();
return super.getStyleableParent();
}
}
int number = 16;
ArrayList<TPane> chain = new ArrayList<>();
TPane top = new TPane("old");
chain.add(top);
TPane p = top;
for (int i = 1; i < number; i++) {
TPane ch = new TPane("old");
p.getChildren().add(ch);
chain.add(ch);
p = ch;
}
scene.setRoot(top);
top.applyCss();
counter.set(0);
// mark the chain dirty
p.getChildren().add(new Pane());
int baseline = counter.get();
for (TPane pane : chain) {
pane.getStyleClass().setAll("new");
}
counter.set(0);
// should not result in quadratic performance
p.getChildren().add(new Pane());
int newCount = counter.get();
assertTrue(newCount <= baseline * 4, () -> {
return MessageFormat.format("Baseline={0}, observed={1}", baseline,
newCount);
});
}
-------------
PR Review Comment: https://git.openjdk.org/jfx/pull/2225#discussion_r3752928982