Well, it is coming as a surprise to many. With the fix for the CSS caching bug since JavaFX 21, this "normal" behavior is becoming much more obvious.

Let me repeat one more time:

If I have a Label, and I manually set its text fill with a setter to YELLOW. In JavaFX 17, when I now add a stylesheet that is empty aside from `-fx-base: WHITE`, the label's text fill stays YELLOW.

Now do this in JavaFX 21.  As soon as you add the stylesheet with `-fx-base: WHITE` in it, the set value to YELLOW is overridden, even though technically this value for -fx-text-fill is defined by Modena (which should not be overriding set values).  Nowhere did we **actualy** override -fx-text-fill, yet the CSS subsystem now sees **all** values defined by Modena that are somehow linked to -fx-base as defined directly by the developer...

The reason this didn't happen in JavaFX prior to 21 is because there was a bug where a CSS value was not fully calculated if the property it encountered was overridden via a set value. That was a bug however as cache entries are shared amongst similar styled nodes, and so not calculating it fully could have effects on other nodes that shared that cache entry but did NOT have a property set directly.  Now that this bug is fixed, this problem is odd behavior is popping up where simply specifying -fx-base in an empty stylesheet is somehow overriding a programmatically set text fill.  Users are confused by this, as nowhere in their stylesheet do they themselves override text fill.

This entire mechanism is not specified by CSS, but is unique to FX.  The most similar mechanism in CSS (see Michael's answer) says the priority of a style should not be changed when it is using a reference.

--John

On 09/07/2024 17:43, Andy Goryachev wrote:

> all styles used in Modena that rely on -fx-base directly or indirectly 
suddenly have a higher priority

I think it works as designed (and as expected).

-andy

*From: *John Hendrikx <john.hendr...@gmail.com>
*Date: *Tuesday, July 9, 2024 at 08:25
*To: *Andy Goryachev <andy.goryac...@oracle.com>, openjfx-dev <openjfx-dev@openjdk.org> *Subject: *[External] : Re: CSS Lookups and their origins (possible regression)

It's not that you can't use -fx-base, but that as it is currently that all styles used in Modena that rely on -fx-base directly or indirectly suddenly have a higher priority (above setters) even though you didn't specifically specify them in your own stylesheet.  All such styles are being elevated from USER_AGENT to AUTHOR level (which is above USER level which is used for setters).

--John

On 09/07/2024 17:03, Andy Goryachev wrote:

    I've used this feature in the past to change the colors in all the
    controls, so to me this is the expected behavior.

    So in your case (if I got it right), you need to set the direct
    style on the label (.setStyle("-fx-text-fill:yellow")) instead of
    setting the text fill programmatically.  Right?

    -andy

    *From: *openjfx-dev <openjfx-dev-r...@openjdk.org>
    <mailto:openjfx-dev-r...@openjdk.org> on behalf of John Hendrikx
    <john.hendr...@gmail.com> <mailto:john.hendr...@gmail.com>
    *Date: *Monday, July 8, 2024 at 17:11
    *To: *openjfx-dev <openjfx-dev@openjdk.org>
    <mailto:openjfx-dev@openjdk.org>
    *Subject: *Re: CSS Lookups and their origins (possible regression)

    I realized I worded the TLDR poorly.

    Let me try again:

    TLDR; should styles which use references (like -fx-base used in
    Modena) become AUTHOR level styles if -fx-base is specified in an
    AUTHOR stylesheet?  The act of simply specifying -fx-base in your
    own AUTHOR stylesheet elevates hundreds of styles from Modena to
    AUTHOR level, as if you specified them directly...

    --John

    On 09/07/2024 02:07, John Hendrikx wrote:

        Hi List,

        TLDR; should a CSS reference like -fx-base convert all styles
        that use this value (or derive from it) become AUTHOR level
        styles (higher priority than setters) ?

        Long version:

        In JavaFX 21, I did a fix (see #1072) to solve a problem where
        a CSS value could be reset on an unrelated control.

        This happened when the CSS engine encountered a stylable that
        is overridden by the user (with a setter), and decided NOT to
        proceed with the full CSS value calculation (as it could not
        override the user setting if that CSS value had lower
        priority).  However, not proceeding with the calculation meant
        that a "SKIP" was stored in a shared cache which was
        incorrect.  This is because when this "SKIP" is later
        encountered for an unrelated control (the cache entries are
        shared for controls with the same styles at the same level),
        they could get their values reset because they were assumed to
        be unstyled.

        However, this fix has exposed what seems to be a deeper bug or
        perhaps an unfortunate default:

        JavaFX has a special feature where you can refer to certain
        other styles by using a reference (which is resolved,
        recursively, to a final value).  This does not seem to be a
        CSS standard, but is a feature only FX has.

        It works by saying something like:

            -fx-base: RED;

        And then using it like this:

            -fx-text-fill: -fx-base;

        This feature works accross stylesheets of different origins,
        so an AUTHOR stylesheet can specify -fx-base, and when a
        USER_AGENT refers to -fx-base, the value comes from the AUTHOR
        stylesheet.

        JavaFX then changes the origin of the style to the highest
        priority encountered while resolving the reference.  This
        means that Modena can specify "-fx-text-fill: -fx-base", and
        when "-fx-base" is then part of the AUTHOR style sheet, that
        ALL Modena styles that use -fx-base will be considered AUTHOR
        level styles, as per this comment:

        // The origin of this parsed value is the greatest of

        // any of the resolved reference. If a resolved reference

        // comes from an inline style, for example, then the value

        // calculated from the resolved lookup should have inline

        // as its origin. Otherwise, an inline style could be

        // stored in shared cache.

        I feel that this is a really unfortunate choice.  The style
        after all was specified by Modena, only its value came from
        another (higher priority) style sheet.  I think a more logical
        choice would have been to not change the priority at all,
        unless a "-fx-text-fill" is explicitly made part of the AUTHOR
        stylesheet.

        A consequence of this (and which is much more visible after
        the fix) is that creating a Label with a
        setTextFill(Color.YELLOW) in its constructor will only result
        in a yellow text fill if the AUTHOR stylesheet did not
        override any of the Modena colors involved in calculating the
        Modena -fx-text-fill default.  Overriding -fx-base in any way
        will result in the text fill of the label to be overridden (as
        the reference came from an AUTHOR stylesheet, which trumps a
        setter which is of a lower style origin).

        The comment also alludes to a potential problem.  If an inline
        style would specify "-fx-base", but would be treated as if it
        came from Modena (USER_AGENT level), then this value could get
        stored in the cache as everything except INLINE styles can be
        cached.  However, I feel that the changing of style origin
        level was then probably done to solve a CACHING problem,
        instead of what made logical sense for users. If we agree that
        a resolved reference should not change the style origin level,
        then this would need to be addressed, by perhaps marking such
        a calculated value as uncacheable, instead of overloading the
        meaning of style origin.

        I'd like to hear your thoughts, and also how to proceed. 
        JavaFX versions before 21 seemingly allowed overriding
        reference without much consequence because if the user
        overrode the value manually, the cache entry would be set to
        "SKIP".  Now that this is no longer the case, JavaFX more
        aggressively overrides user set values if they happen to use a
        referenced value.  See code below.

        --John

        .root {

        -fx-base: #ff0000;

        }

        *package*app;

        *import*javafx.application.Application;

        *import*javafx.scene.Scene;

        *import*javafx.scene.control.Label;

        *import*javafx.scene.paint.Color;

        *import*javafx.stage.Stage;

        *public**class*TestApp *extends*Application {

        *public**static**void*main(String[] args) {

        /launch/(args);

        }

        @Override

        *public**void*start(Stage primaryStage) {

        Scene scene = *new*Scene(*new*MyLabel());

        // See the difference with/without -fx-base in the _stylesheet_

        
scene.getStylesheets().add(TestApp.*class*.getResource("/style.css").toExternalForm());

        primaryStage.setScene(scene);

        primaryStage.show();

        }

        }

        *class*MyLabel *extends*Label {

        *public*MyLabel() {

        setTextFill(Color.YELLOW);

        setText("Hello world");

        }

        }

Reply via email to