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

Reply via email to