-
Notifications
You must be signed in to change notification settings - Fork 473
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8332895: Support interpolation for backgrounds and borders #1471
Conversation
👋 Welcome back mstrauss! A progress list of the required criteria for merging this PR into |
❗ This change is not yet ready to be integrated. |
@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-8332895 with the correct fix version. This pull request cannot be integrated until the CSR request is approved. |
Webrevs
|
First, Thank you for working on these transitions!
Can you elaborate on this? |
I'm not entirely sure what you mean here, but nothing how backgrounds and borders work has changed. Both are still deeply immutable, what's new is that they implement For example, if you want to change the background color of a region, you can't reassign This PR allows the CSS system to also create intermediate backgrounds that represent the transition from one color to the next. The @Override
public Color interpolate(Color endValue, double t) {
if (t <= 0.0) return this;
if (t >= 1.0) return endValue;
...
} However, the current specification of /*
* The function calculates an interpolated value along the fraction
* {@code t} between {@code 0.0} and {@code 1.0}. When {@code t} = 1.0,
* {@code endVal} is returned.
*/ The updated specification is clearer: /**
* Returns an intermediate value between the value of this {@code Interpolatable} and the specified
* {@code endValue} using the linear interpolation factor {@code t}, ranging from 0 (inclusive)
* to 1 (inclusive).
* <p>
* The returned value may not be a new instance; an implementation might also return one of the
* two existing instances if the intermediate value would be equal to one of the existing values.
* However, this is an optimization and applications should not assume any particular identity
* of the returned value.
* <p>
* An implementation is not required to reject interpolation factors less than 0 or larger than 1,
* but this specification gives no meaning to values returned outside of this range. For example,
* an implementation might clamp the interpolation factor to [0..1], or it might continue the linear
* interpolation outside of this range.
*/ |
Ok, great! Thank you for the feedback. |
This seems like a reasonable enhancement. I'll review it (not immediately, though). @nlisker would you be willing to be the second reviewer? A couple general comments:
|
I could do some of the review, but probably no time for a full one.
When I did the (simple) interpolation work on Point2D/3D I also looked at |
There is an issue for that already: https://bugs.openjdk.org/browse/JDK-8226911. You can take it. |
/issue add JDK-8226911 |
@mstr2 |
I've added a new "interpolation type" specification for all components of interpolatable classes. This mirrors the "animation type" of the CSS specification, which is listed as an entry in the property table. Please also read the updated top-level post of this PR, which goes into more detail about this new specification. @kevinrushforth This might be a candidate for a late enhancement, because the risk is relatively low (it's mostly the addition of the |
@@ -184,7 +264,44 @@ public final Color getColor() { | |||
*/ | |||
public Stop(@NamedArg("offset") double offset, @NamedArg(value="color", defaultValue="BLACK") Color color) { | |||
this.offset = offset; | |||
this.color = color; | |||
this.color = Objects.requireNonNullElse(color, Color.TRANSPARENT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that a null
color is now treated as TRANSPARENT
for the following reasons:
- The previous implementation was broken: if a
Stop
is constructed with anull
color, thehashCode()
method throws a NPE because it doesn't check fornull
. - It doesn't make sense to have a stop with
null
color. What does it even mean? - When the stop list is normalized, an empty or null list is treated as a two-stop list with
TRANSPARENT
color (seenormalize()
). So we already have a scenario wherenull
is treated asTRANSPARENT
.
As proposed, this enhancement doesn't cover some edge cases. Back to the drawing board. |
This PR completes the CSS Transitions story (see #870) by adding interpolation support for backgrounds and borders, making them targetable by transitions.
Background
andBorder
objects are deeply immutable, but not interpolatable. Consider the followingBackground
, which describes the background of aRegion
:Since backgrounds are deeply immutable, changing the region's background to another color requires the construction of a new
Background
, containing a newBackgroundFill
, containing the newColor
.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
ImagePattern
LinearGradient
RadialGradient
Stop
Interpolation of composite objects
As of now, only
Color
,Point2D
, andPoint3D
are interpolatable. Each of these classes is an aggregate ofdouble
values, which are combined using linear interpolation. However, many of the new interpolatable classes comprise of not onlydouble
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:Interpolatable
are interpolated by calling theinterpolate(Object, double)}
method.t = 0
produces the start value, andt = 1
produces the end value. This interpolation type is usually applicable for numeric components.t < 0.5
and equal to the end value fort >= 0.5
.Every component of an interpolatable class specifies its interpolation type with the new
@interpolationType
javadoc tag. For example, this is the specification of theCornerRadii.topLeftHorizontalRadius
component:In the generated documentation, this javadoc tag shows up as a new entry in the specification list:
Limitations
Implementations usually fall back to discrete interpolation when the start value is an absolute value, and the end value is a percentage (see the example of
CornerRadii.topLeftHorizontalRadius
above). However, we can often solve these scenarios by first canonicalizing the values before interpolation (i.e. converting percentages to absolute values). This will be a future enhancement./reviewers 2
/csr
Progress
Issues
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1471/head:pull/1471
$ git checkout pull/1471
Update a local copy of the PR:
$ git checkout pull/1471
$ git pull https://git.openjdk.org/jfx.git pull/1471/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1471
View PR using the GUI difftool:
$ git pr show -t 1471
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1471.diff
Webrev
Link to Webrev Comment