RFR: 8332895: Support interpolation for backgrounds and borders [v26]
John Hendrikx
jhendrikx at openjdk.org
Mon Sep 2 15:40:33 UTC 2024
On Sun, 1 Sep 2024 12:31:06 GMT, Michael Strauß <mstrauss at openjdk.org> wrote:
>> This PR completes the CSS Transitions story (see #870) by adding interpolation support for backgrounds and borders, making them targetable by transitions.
>>
>> `Background` and `Border` objects are deeply immutable, but not interpolatable. Consider the following `Background`, which describes the background of a `Region`:
>>
>>
>> Background {
>> fills = [
>> BackgroundFill {
>> fill = Color.RED
>> }
>> ]
>> }
>>
>>
>> Since backgrounds are deeply immutable, changing the region's background to another color requires the construction of a new `Background`, containing a new `BackgroundFill`, containing the new `Color`.
>>
>> Animating the background color using a CSS transition therefore requires the entire Background object graph to be interpolatable in order to generate intermediate backgrounds.
>>
>> More specifically, the following types will now implement `Interpolatable`.
>>
>> - `Insets`
>> - `Background`
>> - `BackgroundFill`
>> - `BackgroundImage`
>> - `BackgroundPosition`
>> - `BackgroundSize`
>> - `Border`
>> - `BorderImage`
>> - `BorderStroke`
>> - `BorderWidths`
>> - `CornerRadii`
>> - `Stop`
>> - `Paint` and all of its subclasses
>> - `Margins` (internal type)
>> - `BorderImageSlices` (internal type)
>>
>> ## Interpolation of composite objects
>>
>> As of now, only `Color`, `Point2D`, and `Point3D` are interpolatable. Each of these classes is an aggregate of `double` values, which are combined using linear interpolation. However, many of the new interpolatable classes comprise of not only `double` values, but a whole range of other types. This requires us to more precisely define what we mean by "interpolation".
>>
>> Mirroring the CSS specification, the `Interpolatable` interface defines several types of component interpolation:
>>
>> | Interpolation type | Description |
>> |---|---|
>> | default | Component types that implement `Interpolatable` are interpolated by calling the `interpolate(Object, double)}` method. |
>> | linear | Two components are combined by linear interpolation such that `t = 0` produces the start value, and `t = 1` produces the end value. This interpolation type is usually applicable for numeric components. |
>> | discrete | If two components cannot be meaningfully combined, the intermediate component value is equal to the start value for `t < 0.5` and equal to the end value for `t >= 0.5`. |
>> | pairwise | Two lists are combined by pairwise interpolation. If the start list has fewer elements than the target list, the...
>
> Michael Strauß has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains 48 additional commits since the last revision:
>
> - Merge branch 'master' into feature/interpolatable
> - remove StyleConverter.WithReconstructionSupport
> - fix line separators
> - StyleableStringProperty should be transitionable
> - non-interpolatable values should always transition discretely
> - only call get() when necessary
> - add more documentation
> - replace reconstruction annotation with interface
> - interpolate integers in real number space
> - replace StyleConverter.SupportsDeconstruction interface with annotation
> - ... and 38 more: https://git.openjdk.org/jfx/compare/37c6136d...2337ca98
Q1: I see a lot of work in the code to handle reverse transitions. Is this actually part of the CSS specification?
Q2: Reversal detection seems very limited. If I change a value multiple times within the duration of the animation, then reset it to its original value, then I think the reversal code will not trigger. As an example, let's say I'm animating scrolling. I'm at the top. I press page down once and then press home. The value changes for example from 0 -> 20 -> 0 -- this triggers the reversal code, and the animated scrolling will quickly return to its top position. However, if I do 0 -> 20 -> 40 -> 0 (page down, page down, home), then I think the reversal is not detected and I'm left with a very slow return to the top position.
Q3: How does the user do calculations for properties that are being interpolated? Let's say I have a simple system where the `+` and `-` change a value by +10 and -10. So I press `+`; I read the current value, add 10 and set it (say from 0 to 10). Now I press `+` again. Reading the current value would get me some intermediate animated value. Adding 10 to this is not what the user would expect (they would expect to go to 20, not to 15 if the animation was only halfway completed).
As an example, I've implemented (without CSS transitions) a smooth scrolling system; this system tracks the target value to do the scrolling. Pressing 3x page down in a row will go 3 pages down, no matter what the state of the animation. With CSS transitions, should the programmer be aware of the interpolation (which may be added later in CSS) and track their own "target" value to make this work as you'd expect?
-------------
PR Comment: https://git.openjdk.org/jfx/pull/1522#issuecomment-2325001849
More information about the openjfx-dev
mailing list