Skip to content
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 #1522

Closed
wants to merge 67 commits into from
Closed
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
25bcb1d
Add interpolation support for backgrounds and borders
mstr2 Jun 2, 2024
e795fd0
add since tags
mstr2 Jun 4, 2024
bb84c57
clean up imports
mstr2 Jun 4, 2024
4f363a4
Merge branch 'master' into feature/interpolatable
mstr2 Jul 4, 2024
e7e5fac
added specification and tests
mstr2 Jul 4, 2024
3221441
added more tests
mstr2 Jul 4, 2024
5f63c28
revert change
mstr2 Jul 4, 2024
47e55bf
revert change
mstr2 Jul 4, 2024
1cebcc1
add exports
mstr2 Jul 4, 2024
831cf6b
add specification
mstr2 Jul 4, 2024
1efce84
change documentation
mstr2 Jul 4, 2024
12a73d5
add documentation to Point2D/3D
mstr2 Jul 4, 2024
08ed751
fix line separators
mstr2 Jul 4, 2024
6dbefb8
ComponentTransitionable implementation
mstr2 Jul 30, 2024
bbfb025
fix line separators
mstr2 Jul 30, 2024
ab8480a
Merge branch 'master' into feature/interpolatable
mstr2 Jul 30, 2024
1cc8db8
add tests
mstr2 Jul 30, 2024
7650fea
documentation
mstr2 Jul 30, 2024
94d6a90
fix line separators
mstr2 Jul 30, 2024
675bc7f
fixed a bug
mstr2 Jul 31, 2024
64e4f17
adjust table styling
mstr2 Aug 2, 2024
7a92bbf
fix since tag
mstr2 Aug 2, 2024
8f53f3a
add test for inherited transitions
mstr2 Aug 2, 2024
bd4c2c3
remove redundant null initialization
mstr2 Aug 2, 2024
3b8fa91
update documentation
mstr2 Aug 2, 2024
10705a3
address review comments
mstr2 Aug 2, 2024
3d12f77
use switch instead of nested if
mstr2 Aug 3, 2024
6667dd5
use switch instead of nested if
mstr2 Aug 3, 2024
14e91f1
fix trailing whitespace
mstr2 Aug 3, 2024
4257d2f
move interpolation helpers to separate file
mstr2 Aug 4, 2024
843713b
added comments
mstr2 Aug 4, 2024
0def5d1
move tests
mstr2 Aug 4, 2024
3437267
remove ComponentTransitionable
mstr2 Aug 4, 2024
b545617
add tests
mstr2 Aug 4, 2024
a2d0d6c
add test for stop lists
mstr2 Aug 4, 2024
d7f2187
use HashMap.newHashMap()
mstr2 Aug 4, 2024
2f03e13
add export
mstr2 Aug 6, 2024
eb9700a
Merge branch 'refs/heads/master' into feature/interpolatable
mstr2 Aug 6, 2024
61d595f
replace StyleConverter.SupportsDeconstruction interface with annotation
mstr2 Aug 6, 2024
c36c6c0
interpolate integers in real number space
mstr2 Aug 7, 2024
03c5496
replace reconstruction annotation with interface
mstr2 Aug 7, 2024
2bc0000
add more documentation
mstr2 Aug 8, 2024
1abd688
only call get() when necessary
mstr2 Aug 8, 2024
abef432
non-interpolatable values should always transition discretely
mstr2 Aug 9, 2024
7288fcc
StyleableStringProperty should be transitionable
mstr2 Aug 9, 2024
a0557b8
fix line separators
mstr2 Aug 9, 2024
9bdea0a
remove StyleConverter.WithReconstructionSupport
mstr2 Aug 9, 2024
2337ca9
Merge branch 'master' into feature/interpolatable
mstr2 Sep 1, 2024
6218e9a
address review comments
mstr2 Sep 3, 2024
74b23c4
typo
mstr2 Sep 3, 2024
ba375b5
refactoring
mstr2 Sep 3, 2024
97ee29e
changes per review
mstr2 Sep 5, 2024
7328daa
address review comments
mstr2 Sep 5, 2024
9b7f2a5
javadoc changes
mstr2 Sep 5, 2024
d884a56
added tests
mstr2 Sep 5, 2024
75e7d98
javadoc changes
mstr2 Sep 5, 2024
acdec11
fixed a bug when null values require discrete transitions
mstr2 Sep 6, 2024
f9187a1
small doc changes, copyright header
mstr2 Sep 8, 2024
c9cf139
javadoc change
mstr2 Sep 14, 2024
1227a79
javadoc change
mstr2 Sep 14, 2024
1c842cc
javadoc change
mstr2 Sep 16, 2024
6b90089
Merge branch 'master' into feature/interpolatable
mstr2 Sep 25, 2024
3027caa
fix merge conflicts
mstr2 Sep 25, 2024
bb0cc60
documentation changes
mstr2 Sep 27, 2024
e3792cc
documentation changes
mstr2 Sep 27, 2024
7d086cf
removed unnecessary imports
mstr2 Sep 27, 2024
332a5c1
added @deprecated javadoc tag
mstr2 Sep 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4375,6 +4375,7 @@ task javadoc(type: Javadoc, dependsOn: createMSPfile) {
options.tags("apiNote:a:API Note:")
options.tags("implSpec:a:Implementation Requirements:")
options.tags("implNote:a:Implementation Note:")
options.tags("interpolationType:a:Interpolation Type:")
options.tags("param")
options.tags("return")
options.tags("throws")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -26,6 +26,8 @@
package com.sun.javafx;

import java.util.AbstractList;
import java.util.List;
import java.util.Objects;
import java.util.RandomAccess;

/**
Expand Down Expand Up @@ -60,4 +62,64 @@ public UnmodifiableArrayList(T[] elements, int size) {
@Override public int size() {
return size;
}

/**
* Converts the specified list into an unmodifiable list that does not contain {@code null} values.
* The returned list is a copy of, and not a wrapper around the specified list.
*
* @param <T> the type of elements in the list
* @param list the list, not {@code null}
* @return an unmodifiable list that does not contain null values
*/
public static <T> UnmodifiableArrayList<T> copyOfNullFiltered(List<T> list) {
Objects.requireNonNull(list, "list cannot be null");

int numNonNullValues = 0;

@SuppressWarnings("unchecked")
T[] newValues = (T[])new Object[list.size()];
mstr2 marked this conversation as resolved.
Show resolved Hide resolved

if (list instanceof RandomAccess) {
// Prevents the iterator allocation for random-access lists.
for (int i = 0, max = list.size(); i < max; ++i) {
T value = list.get(i);
if (value != null) {
newValues[numNonNullValues++] = value;
}
}
} else {
for (T value : list) {
if (value != null) {
newValues[numNonNullValues++] = value;
}
}
}

return new UnmodifiableArrayList<>(newValues, numNonNullValues);
}

/**
* Converts the specified array into an unmodifiable list that does not contain {@code null} values.
* The returned list is a copy of, and not a wrapper around the specified array.
*
* @param <T> the type of elements in the array
* @param elements the array, not {@code null}
* @return an unmodifiable list that does not contain null values
*/
public static <T> UnmodifiableArrayList<T> copyOfNullFiltered(T[] elements) {
Objects.requireNonNull(elements, "elements cannot be null");

int numNonNullValues = 0;

@SuppressWarnings("unchecked")
T[] newValues = (T[])new Object[elements.length];

for (int i = 0; i < elements.length; ++i) {
if (elements[i] != null) {
newValues[numNonNullValues++] = elements[i];
}
}

return new UnmodifiableArrayList<>(newValues, numNonNullValues);
}
}
1 change: 1 addition & 0 deletions modules/javafx.base/src/test/addExports
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#
--add-exports javafx.base/com.sun.javafx=ALL-UNNAMED
--add-exports javafx.base/com.sun.javafx.binding=ALL-UNNAMED
--add-exports javafx.base/com.sun.javafx.collections=ALL-UNNAMED
--add-exports javafx.base/com.sun.javafx.event=ALL-UNNAMED
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package test.com.sun.javafx;

import com.sun.javafx.UnmodifiableArrayList;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

public class UnmodifiableArrayListTest {

@Test
void testCopyOfNullFilteredList_nullList() {
assertThrows(NullPointerException.class, () -> UnmodifiableArrayList.copyOfNullFiltered((List<?>)null));
}

@Test
void testCopyOfNullFilteredList_nullArray() {
assertThrows(NullPointerException.class, () -> UnmodifiableArrayList.copyOfNullFiltered((Object[])null));
}

@Test
void testCopyOfNullFilteredList_randomAccess() {
var list = new ArrayList<String>();
list.add("a");
list.add(null);
list.add("b");
list.add(null);

assertEquals(List.of("a", "b"), UnmodifiableArrayList.copyOfNullFiltered(list));
}

@Test
void testCopyOfNullFilteredList_nonRandomAccess() {
var list = new LinkedList<String>();
list.add("a");
list.add(null);
list.add("b");
list.add(null);

assertEquals(List.of("a", "b"), UnmodifiableArrayList.copyOfNullFiltered(list));
}

@Test
void testCopyOfNullFilteredArray() {
var list = new String[4];
list[0] = "a";
list[1] = null;
list[2] = "b";
list[3] = null;

assertEquals(List.of("a", "b"), UnmodifiableArrayList.copyOfNullFiltered(list));
}
}
64 changes: 64 additions & 0 deletions modules/javafx.base/src/test/java/test/util/ReflectionUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package test.util;

import java.lang.reflect.Field;
import java.util.function.Function;

public final class ReflectionUtils {

/**
* Returns the value of a potentially private field of the specified object.
* The field can be declared on any of the object's inherited classes.
*/
public static Object getFieldValue(Object object, String fieldName) {
Function<Class<?>, Field> getField = cls -> {
try {
var field = cls.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
return null;
}
};

Class<?> cls = object.getClass();
while (cls != null) {
Field field = getField.apply(cls);
if (field != null) {
try {
return field.get(object);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}

cls = cls.getSuperclass();
}

throw new AssertionError("Field not found: " + fieldName);
}
}
2 changes: 1 addition & 1 deletion modules/javafx.graphics/.classpath
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<classpathentry combineaccessrules="false" kind="src" path="/base">
<attributes>
<attribute name="module" value="true"/>
<attribute name="add-exports" value="javafx.base/com.sun.javafx.property=javafx.graphics:javafx.base/test.javafx.collections=javafx.graphics:javafx.base/test.util.memory=javafx.graphics"/>
<attribute name="add-exports" value="javafx.base/com.sun.javafx.property=javafx.graphics:javafx.base/test.javafx.collections=javafx.graphics:javafx.base/test.util.memory=javafx.graphics:javafx.base/test.util=javafx.graphics"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package com.sun.javafx.css;

import javafx.css.CssMetaData;
import javafx.css.Styleable;
import java.util.Map;

/**
* Defines the {@code convert} and {@code convertBack} operations that enable object
* decomposition and reconstruction. Note that the following invariant must always be
* satisfied: {@code convert(convertBack(value)).equals(value)}
*
* @param <T> the target type
*/
public interface SubPropertyConverter<T> {

/**
* Converts a map of CSS values to the target type.
*
* @param values the constituent values
* @throws NullPointerException if {@code values} is {@code null}
* @return the converted object
*/
T convert(Map<CssMetaData<? extends Styleable, ?>, Object> values);

/**
* Converts an object back to a map of its constituent values (deconstruction).
* The returned map can be passed into {@link #convert(Map)} to reconstruct the object.
*
* @param value the object
* @throws NullPointerException if {@code value} is {@code null}
* @return a {@code Map} of the constituent values
*/
Map<CssMetaData<? extends Styleable, ?>, Object> convertBack(T value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,42 +32,33 @@
*/
public abstract class TransitionMediator {

private TransitionTimer timer;
private TransitionTimer.CancellationToken cancellationToken;

/**
* Starts the transition timer with the specified transition definition.
*
* @param definition the transition definition
* @param targetPropertyName the name of the targeted CSS property
* @param nanoNow the current time in nanoseconds
*/
public final void run(TransitionDefinition definition) {
public final void run(TransitionDefinition definition, String targetPropertyName, long nanoNow) {
// Might return 'null' if the transition duration is zero or the target node is not showing.
timer = TransitionTimer.run(this, definition);
cancellationToken = TransitionTimer.run(this, definition, targetPropertyName, nanoNow);

// If no timer was started, we complete the transition immediately.
if (timer == null) {
if (cancellationToken == null) {
onUpdate(1);
onStop();
}
}

/**
* Cancels the transition timer.
*
* @param forceStop if {@code true}, the transition timer is stopped unconditionally
* @return {@code true} if the timer was cancelled, {@code false} otherwise
* @see TransitionTimer#cancel(boolean)
*/
public final boolean cancel(boolean forceStop) {
return timer == null || timer.cancel(forceStop);
}

/**
* Gets the running {@code TransitionTimer}.
*
* @return the {@code TransitionTimer}, or {@code null} if no timer is running
* Cancels the transition timer if it is currently running.
*/
public final TransitionTimer getTimer() {
return timer;
public final void cancel() {
if (cancellationToken != null) {
cancellationToken.cancel();
}
}

/**
Expand All @@ -90,4 +81,21 @@ public final TransitionTimer getTimer() {
* Derived classes should implement this method to clear any references to this mediator.
*/
public abstract void onStop();

/**
* Derived classes must implement the following protocol:
* <ol>
* <li>If the reversing-adjusted start value of the existing transition is equal
* to the end value of this transition:
* Set the reversing-adjusted start value of this transition to the end value
* of the existing transition and return {@code true}.
* <li>Otherwise, return {@code false}.
* </ol>
* Refer to <a href="https://www.w3.org/TR/css-transitions-1/#starting">Starting of transitions</a>
* for more information about the reversing-adjusted start value.
*
* @param existingMediator the mediator of the existing transition
* @return {@code true} if the reversing-adjusted start value was updated, {@code false} otherwise
*/
public abstract boolean updateReversingAdjustedStartValue(TransitionMediator existingMediator);
}
Loading