RFR: 8375363: StyleHelper.resetToInitialValues() interrupts animated properties
Michael Strauß
mstrauss at openjdk.org
Thu Jan 15 03:16:11 UTC 2026
In the following program, resizing the window to be smaller than 300px should start a transition for `-fx-scale-x` from 2 to 1, but instead the value sometimes snaps back to 1 instantly:
public class InterruptedTransitionBug extends Application {
@Override
public void start(Stage stage) throws Exception {
var root = new StackPane(new Button("My Button"));
var scene = new Scene(root, 600, 200);
scene.getStylesheets().add("data:text/css;base64," + Base64.getEncoder().encodeToString("""
.button {
transition: -fx-scale-x 2s;
}
@media (width > 300px) {
.button {
-fx-scale-x: 2;
}
}
""".getBytes(StandardCharsets.UTF_8)));
stage.setScene(scene);
stage.show();
}
}
### Problem
First, let's look at how `CssStyleHelper` works when the cascading style map for a node changes:
1. When the style map for a node has changed, `StyleHelper.createStyleHelper(Node)` determines that the style helper is no longer any good, and a new `CssStyleHelper` for the new style map is created.
2. Before the old style helper is discarded, it calls `CssStyleHelper.resetToInitialValues(Styleable)` and resets all properties that were set by this style helper back to their initial values. This ensures that the new style helper has a "clean slate" to work from.
3. The next `Node.applyCss()` pass will now set the properties that are specified in the new style map to their new values.
However, when transitions come into play, this mechanism can break:
1. In our example, the `Button` starts with a style map that contains two properties:
* `transition: -fx-scale-x 2s`
* `-fx-scale-x: 2`
2. Due to a changing media query, this is replaced with a style map that only contains a single entry:
* `transition: -fx-scale-x 2s`
3. Before the new style map is applied, all properties affected by the old style map are reset to their initial values. That means:
* `-fx-scale-x` is reset to `1`
* `transition` is reset to `null`
This is where it breaks: if `transition` is reset before `-fx-scale-x`, the latter will see no transition when its value is set back to `1`.
### Solution
Simply resetting all properties back to their initial values when a style map is changed is not necessary. We only need to reset the properties that are set by the old style map, but are no longer set by the new style map. In our example, since the `transition` property is set by both the old and the new style map, we don't reset it: its new value will be calculated in the next `Node.applyCss()` pass.
When a property is set by CSS, we also need to make sure that when we ask "has the property actually changed?" we compare the calculated value to the _after-change style_ value of the property, and not to its current (potentially animating) value.
-------------
Commit messages:
- fix
Changes: https://git.openjdk.org/jfx/pull/2038/files
Webrev: https://webrevs.openjdk.org/?repo=jfx&pr=2038&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8375363
Stats: 403 lines in 10 files changed: 357 ins; 16 del; 30 mod
Patch: https://git.openjdk.org/jfx/pull/2038.diff
Fetch: git fetch https://git.openjdk.org/jfx.git pull/2038/head:pull/2038
PR: https://git.openjdk.org/jfx/pull/2038
More information about the openjfx-dev
mailing list