jfx icon indicating copy to clipboard operation
jfx copied to clipboard

8358820: Allow interpolation outside of range [0,1]

Open mstr2 opened this issue 6 months ago • 7 comments

JavaFX unnecessarily restricts interpolation in the following ways:

  1. Interpolatable implementations often clamp intermediate values to the interpolation factor range [0,1].
  2. SplineInterpolator doesn't accept Y coordinates outside of [0,1] for its control points. While this was probably done so that the computed interpolation factor doesn't exceed [0,1], the restriction goes far beyond that. For example, the following function is not representable, even though its values are all within the [0,1] range:

    The following function is also not representable, but would be very useful for bouncy animations:

Fortunately, there is no technical reason why JavaFX can't support the full range of animations that can be represented with a cubic Beziér interpolation function.

This PR includes the following changes:

  1. The specification of Interpolatable is changed to require implementations to accept interpolation factors outside of [0,1].
  2. All implementations of Interpolatable now correctly return intermediate values outside of [0,1].
  3. SplineInterpolator now accepts control points with any Y coordinate.

Here's how the result looks like for the previously unrepresentable interpolation function cubic-bezier(0.34, 2.2, 0.64, 1):

/reviewers 2 /csr


Progress

  • [ ] Change requires a CSR request matching fixVersion jfx25 to be approved (needs to be created)
  • [x] Change must not contain extraneous whitespace
  • [x] Commit message must refer to an issue
  • [ ] Change must be properly reviewed (2 reviews required, with at least 1 Reviewer, 1 Author)

Issue

  • JDK-8358820: Allow interpolation outside of range [0,1] (Enhancement - P4)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1822/head:pull/1822
$ git checkout pull/1822

Update a local copy of the PR:
$ git checkout pull/1822
$ git pull https://git.openjdk.org/jfx.git pull/1822/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 1822

View PR using the GUI difftool:
$ git pr show -t 1822

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1822.diff

Using Webrev

Link to Webrev Comment

mstr2 avatar Jun 06 '25 23:06 mstr2

:wave: Welcome back mstrauss! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

bridgekeeper[bot] avatar Jun 06 '25 23:06 bridgekeeper[bot]

@mstr2 This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8358820: Allow interpolation outside of range [0,1]

Reviewed-by: angorya, kcr

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 20 new commits pushed to the master branch:

  • 9a4b601a7d3ea0ddfb001d27eecdc2ee4185298c: 8365402: Bump minimum JDK version for JavaFX to JDK 24
  • 368bd20b887bb813718fbfecc14760597e8d4521: 8322486: ColorPicker: blurry popup
  • fa2127cb3a3fc11238c5c8ce4cf0d15c4000f05c: 8365576: Temporarily make Metal the default JavaFX rendering pipeline for macOS
  • ... and 17 more: https://git.openjdk.org/jfx/compare/bc433da812461a1c2796cdb3123f814e4ce532d5...master

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

openjdk[bot] avatar Jun 06 '25 23:06 openjdk[bot]

@mstr2 The total number of required reviews for this PR (including the jcheck configuration and the last /reviewers command) is now set to 2 (with at least 1 Reviewer, 1 Author).

openjdk[bot] avatar Jun 06 '25 23:06 openjdk[bot]

@mstr2 has indicated that a compatibility and specification (CSR) request is needed for this pull request.

@mstr2 please create a CSR request for issue JDK-8358820 with the correct fix version. This pull request cannot be integrated until the CSR request is approved.

openjdk[bot] avatar Jun 06 '25 23:06 openjdk[bot]

Noting that this proposed change supersedes the previous changes that were done for for https://bugs.openjdk.org/browse/JDK-8226911. The proposed behavioral change makes sense.

nlisker avatar Jun 07 '25 18:06 nlisker

Noting that this proposed change supersedes the previous changes that were done for for https://bugs.openjdk.org/browse/JDK-8226911. The proposed behavioral change makes sense.

Can I interest you in a review of the API and/or the implementation?

mstr2 avatar Jun 13 '25 15:06 mstr2

@mstr2 This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply issue a /touch or /keepalive command to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

bridgekeeper[bot] avatar Jul 25 '25 10:07 bridgekeeper[bot]

Currently the workaround I use for this is to have a custom Interpolator implementation like:

public class Cubic extends Interpolator {
    private final double x1;
    private final double y1;
    private final double x2;
    private final double y2;

    private static final double CUBIC_ERROR_BOUND = 0.001;

    public Cubic(double x1, double y1, double x2, double y2) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }

    double elevateCubic(double a, double b, double m) {
        return 3 * a * (1 - m) * (1 - m) * m +
               3 * b * (1 - m) * m * m +
               m * m * m;
    }

    @Override
    public double curve(double t) {
        double start = 0.0;
        double end = 1.0;
        while (true) {
            final double midpoint = (start + end) / 2;
            final double estimate = elevateCubic(x1, x2, midpoint);
            if (Math.abs(t - estimate) < CUBIC_ERROR_BOUND) {
                return elevateCubic(y1, y2, midpoint);
            }
            if (estimate < t) {
                start = midpoint;
            } else {
                end = midpoint;
            }
        }
    }
}

Which allows me to define such curves:

    public static final MotionPreset EXPRESSIVE_FAST_SPATIAL = MotionPreset.of(
        new Cubic(0.42, 1.67, 0.21, 0.90),
        MEDIUM3 // Duration constant
    );

I believe I copied this from Flutter. (The new Material 3 Expressive makes use a lot of springs, see Material 3 Docs)

Unfortunately, I need to use such curves in CSS too, so I kinda need this commit to be merged

palexdev avatar Aug 22 '25 07:08 palexdev

The API spec changes look good. I left a comment in the CSR that you need to add the changes made to RadialGradient (it looks good otherwise).

I spot checked the implementation and it all looks like what I expect. I'll finish reviewing and testing today.

kevinrushforth avatar Sep 05 '25 14:09 kevinrushforth

/integrate

mstr2 avatar Sep 08 '25 21:09 mstr2

Going to push as commit 999c396d3c8d76be5b25c08e66490f026ae7b99a. Since your change was applied there have been 20 commits pushed to the master branch:

  • 9a4b601a7d3ea0ddfb001d27eecdc2ee4185298c: 8365402: Bump minimum JDK version for JavaFX to JDK 24
  • 368bd20b887bb813718fbfecc14760597e8d4521: 8322486: ColorPicker: blurry popup
  • fa2127cb3a3fc11238c5c8ce4cf0d15c4000f05c: 8365576: Temporarily make Metal the default JavaFX rendering pipeline for macOS
  • ... and 17 more: https://git.openjdk.org/jfx/compare/bc433da812461a1c2796cdb3123f814e4ce532d5...master

Your commit was automatically rebased without conflicts.

openjdk[bot] avatar Sep 08 '25 21:09 openjdk[bot]

@mstr2 Pushed as commit 999c396d3c8d76be5b25c08e66490f026ae7b99a.

:bulb: You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

openjdk[bot] avatar Sep 08 '25 21:09 openjdk[bot]