diff --git a/modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/cssref.html b/modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/cssref.html
index 27abfac7585..f57e5cf317e 100644
--- a/modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/cssref.html
+++ b/modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/cssref.html
@@ -1882,11 +1882,34 @@
- -fx-image |
+ -fx-fit-height |
+ <number> |
+ 0 |
+ The height of the bounding box within which the source image is resized as necessary to fit. |
+
+
+ -fx-fit-width |
+ <number> |
+ 0 |
+ The width of the bounding box within which the source image is resized as necessary to fit. |
+
+ -fx-image |
<uri> |
null |
Relative URLs are resolved against the URL of the stylesheet. |
+
+ -fx-preserve-ratio |
+ <boolean> |
+ false |
+ Indicates whether to preserve the aspect ratio of the source image when scaling to fit the image within the fitting bounding box. |
+
+
+ -fx-smooth |
+ <boolean> |
+ Platform-specific |
+ Indicates whether to use a better quality filtering algorithm or a faster one when transforming or scaling the source image to fit. |
+
Also has all properties of Node |
diff --git a/modules/javafx.graphics/src/main/java/com/sun/javafx/css/CssUtil.java b/modules/javafx.graphics/src/main/java/com/sun/javafx/css/CssUtil.java
new file mode 100644
index 00000000000..af44bf76aaf
--- /dev/null
+++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/css/CssUtil.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2023, 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 java.util.List;
+import javafx.css.CssMetaData;
+import javafx.css.Styleable;
+import javafx.scene.Node;
+
+/**
+ * Utility methods for dealing with CSS.
+ */
+public final class CssUtil {
+
+ private CssUtil() {
+ }
+
+ /**
+ * Utility method which combines {@code CssMetaData} items in one immutable list.
+ *
+ * The intended usage is to combine the parent and the child {@code CssMetaData} for
+ * the purposes of {@code getClassCssMetaData()} method, see for example {@link Node#getClassCssMetaData()}.
+ *
+ * Example:
+ *
{@code
+ * private static final List> STYLEABLES = CssMetaData.combine(
+ * .getClassCssMetaData(),
+ * STYLEABLE1,
+ * STYLEABLE2
+ * );
+ * }
+ * This method returns an instance of a {@code List} that implements
+ * {@link java.util.RandomAccess} interface.
+ *
+ * @param inheritedFromParent the {@code CssMetaData} items inherited from parent, must not be null
+ * @param items the additional items
+ * @return the immutable list containing all of the items
+ */
+ // NOTE: this should be a public utility, see https://bugs.openjdk.org/browse/JDK-8320796
+ public static List> combine(
+ List> inheritedFromParent,
+ CssMetaData extends Styleable, ?>... items)
+ {
+ CssMetaData[] combined = new CssMetaData[inheritedFromParent.size() + items.length];
+ inheritedFromParent.toArray(combined);
+ System.arraycopy(items, 0, combined, inheritedFromParent.size(), items.length);
+ return List.of(combined);
+ }
+}
diff --git a/modules/javafx.graphics/src/main/java/javafx/scene/image/ImageView.java b/modules/javafx.graphics/src/main/java/javafx/scene/image/ImageView.java
index 0c59aa5e140..70ef84a9b94 100644
--- a/modules/javafx.graphics/src/main/java/javafx/scene/image/ImageView.java
+++ b/modules/javafx.graphics/src/main/java/javafx/scene/image/ImageView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2023, 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
@@ -25,31 +25,39 @@
package javafx.scene.image;
-import com.sun.javafx.beans.event.AbstractNotifyListener;
-import com.sun.javafx.css.StyleManager;
-import javafx.css.converter.URLConverter;
-import com.sun.javafx.geom.BaseBounds;
-import com.sun.javafx.geom.transform.BaseTransform;
-import com.sun.javafx.scene.DirtyBits;
-import com.sun.javafx.scene.ImageViewHelper;
-import com.sun.javafx.scene.NodeHelper;
-import com.sun.javafx.sg.prism.NGImageView;
-import com.sun.javafx.sg.prism.NGNode;
-import com.sun.javafx.tk.Toolkit;
+import java.util.List;
import javafx.beans.DefaultProperty;
import javafx.beans.Observable;
-import javafx.beans.property.*;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.DoublePropertyBase;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.ObjectPropertyBase;
+import javafx.beans.property.StringProperty;
import javafx.css.CssMetaData;
import javafx.css.Styleable;
+import javafx.css.StyleableBooleanProperty;
+import javafx.css.StyleableDoubleProperty;
import javafx.css.StyleableProperty;
import javafx.css.StyleableStringProperty;
+import javafx.css.converter.BooleanConverter;
+import javafx.css.converter.SizeConverter;
+import javafx.css.converter.URLConverter;
import javafx.geometry.NodeOrientation;
import javafx.geometry.Rectangle2D;
import javafx.scene.AccessibleRole;
import javafx.scene.Node;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import com.sun.javafx.beans.event.AbstractNotifyListener;
+import com.sun.javafx.css.CssUtil;
+import com.sun.javafx.css.StyleManager;
+import com.sun.javafx.geom.BaseBounds;
+import com.sun.javafx.geom.transform.BaseTransform;
+import com.sun.javafx.scene.DirtyBits;
+import com.sun.javafx.scene.ImageViewHelper;
+import com.sun.javafx.scene.NodeHelper;
+import com.sun.javafx.sg.prism.NGImageView;
+import com.sun.javafx.sg.prism.NGNode;
+import com.sun.javafx.tk.Toolkit;
/**
* The {@code ImageView} is a {@code Node} used for painting images loaded with
@@ -408,8 +416,7 @@ public String getName() {
*
* @defaultValue 0
*/
- private DoubleProperty fitWidth;
-
+ private StyleableDoubleProperty fitWidth;
public final void setFitWidth(double value) {
fitWidthProperty().set(value);
@@ -421,8 +428,7 @@ public final double getFitWidth() {
public final DoubleProperty fitWidthProperty() {
if (fitWidth == null) {
- fitWidth = new DoublePropertyBase() {
-
+ fitWidth = new StyleableDoubleProperty() {
@Override
protected void invalidated() {
invalidateWidthHeight();
@@ -439,6 +445,11 @@ public Object getBean() {
public String getName() {
return "fitWidth";
}
+
+ @Override
+ public CssMetaData extends Styleable, Number> getCssMetaData() {
+ return StyleableProperties.FIT_WIDTH;
+ }
};
}
return fitWidth;
@@ -456,8 +467,7 @@ public String getName() {
*
* @defaultValue 0
*/
- private DoubleProperty fitHeight;
-
+ private StyleableDoubleProperty fitHeight;
public final void setFitHeight(double value) {
fitHeightProperty().set(value);
@@ -469,8 +479,7 @@ public final double getFitHeight() {
public final DoubleProperty fitHeightProperty() {
if (fitHeight == null) {
- fitHeight = new DoublePropertyBase() {
-
+ fitHeight = new StyleableDoubleProperty() {
@Override
protected void invalidated() {
invalidateWidthHeight();
@@ -487,6 +496,11 @@ public Object getBean() {
public String getName() {
return "fitHeight";
}
+
+ @Override
+ public CssMetaData extends Styleable, Number> getCssMetaData() {
+ return StyleableProperties.FIT_HEIGHT;
+ }
};
}
return fitHeight;
@@ -521,8 +535,7 @@ public String getName() {
*
* @defaultValue false
*/
- private BooleanProperty preserveRatio;
-
+ private StyleableBooleanProperty preserveRatio;
public final void setPreserveRatio(boolean value) {
preserveRatioProperty().set(value);
@@ -534,8 +547,7 @@ public final boolean isPreserveRatio() {
public final BooleanProperty preserveRatioProperty() {
if (preserveRatio == null) {
- preserveRatio = new BooleanPropertyBase() {
-
+ preserveRatio = new StyleableBooleanProperty() {
@Override
protected void invalidated() {
invalidateWidthHeight();
@@ -552,6 +564,11 @@ public Object getBean() {
public String getName() {
return "preserveRatio";
}
+
+ @Override
+ public CssMetaData extends Styleable, Boolean> getCssMetaData() {
+ return StyleableProperties.PRESERVE_RATIO;
+ }
};
}
return preserveRatio;
@@ -573,8 +590,7 @@ public String getName() {
*
* @defaultValue platform-dependent
*/
- private BooleanProperty smooth;
-
+ private StyleableBooleanProperty smooth;
public final void setSmooth(boolean value) {
smoothProperty().set(value);
@@ -586,8 +602,7 @@ public final boolean isSmooth() {
public final BooleanProperty smoothProperty() {
if (smooth == null) {
- smooth = new BooleanPropertyBase(SMOOTH_DEFAULT) {
-
+ smooth = new StyleableBooleanProperty(SMOOTH_DEFAULT) {
@Override
protected void invalidated() {
NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_SMOOTH);
@@ -602,6 +617,11 @@ public Object getBean() {
public String getName() {
return "smooth";
}
+
+ @Override
+ public CssMetaData extends Styleable, Boolean> getCssMetaData() {
+ return StyleableProperties.SMOOTH;
+ }
};
}
return smooth;
@@ -804,16 +824,38 @@ private boolean doComputeContains(double localX, double localY) {
private static final String DEFAULT_STYLE_CLASS = "image-view";
- /*
- * Super-lazy instantiation pattern from Bill Pugh.
- */
- private static class StyleableProperties {
- // TODO
- // "preserve-ratio","smooth","viewport","fit-width","fit-height"
- private static final CssMetaData IMAGE =
- new CssMetaData<>("-fx-image",
- URLConverter.getInstance()) {
+ private static class StyleableProperties {
+ private static final CssMetaData FIT_HEIGHT =
+ new CssMetaData<>("-fx-fit-height", SizeConverter.getInstance(), 0.0)
+ {
+ @Override
+ public boolean isSettable(ImageView n) {
+ return n.fitHeight == null || !n.fitHeight.isBound();
+ }
+
+ @Override
+ public StyleableProperty getStyleableProperty(ImageView n) {
+ return (StyleableProperty)n.fitHeightProperty();
+ }
+ };
+
+ private static final CssMetaData FIT_WIDTH =
+ new CssMetaData<>("-fx-fit-width", SizeConverter.getInstance(), 0.0)
+ {
+ @Override
+ public boolean isSettable(ImageView n) {
+ return n.fitWidth == null || !n.fitWidth.isBound();
+ }
+
+ @Override
+ public StyleableProperty getStyleableProperty(ImageView n) {
+ return (StyleableProperty)n.fitWidthProperty();
+ }
+ };
+ private static final CssMetaData IMAGE =
+ new CssMetaData<>("-fx-image", URLConverter.getInstance())
+ {
@Override
public boolean isSettable(ImageView n) {
// Note that we care about the image, not imageUrl
@@ -826,13 +868,42 @@ public StyleableProperty getStyleableProperty(ImageView n) {
}
};
- private static final List> STYLEABLES;
- static {
- final List> styleables =
- new ArrayList<>(Node.getClassCssMetaData());
- styleables.add(IMAGE);
- STYLEABLES = Collections.unmodifiableList(styleables);
- }
+ private static final CssMetaData PRESERVE_RATIO =
+ new CssMetaData<>("-fx-preserve-ratio", BooleanConverter.getInstance(), Boolean.FALSE)
+ {
+ @Override
+ public boolean isSettable(ImageView n) {
+ return n.preserveRatio == null || !n.preserveRatio.isBound();
+ }
+
+ @Override
+ public StyleableProperty getStyleableProperty(ImageView n) {
+ return (StyleableProperty)n.preserveRatioProperty();
+ }
+ };
+
+ private static final CssMetaData SMOOTH =
+ new CssMetaData<>("-fx-smooth", BooleanConverter.getInstance(), SMOOTH_DEFAULT)
+ {
+ @Override
+ public boolean isSettable(ImageView n) {
+ return n.smooth == null || !n.smooth.isBound();
+ }
+
+ @Override
+ public StyleableProperty getStyleableProperty(ImageView n) {
+ return (StyleableProperty)n.smoothProperty();
+ }
+ };
+
+ private static final List> STYLEABLES = CssUtil.combine(
+ Node.getClassCssMetaData(),
+ FIT_HEIGHT,
+ FIT_WIDTH,
+ IMAGE,
+ PRESERVE_RATIO,
+ SMOOTH
+ );
}
/**
diff --git a/modules/javafx.graphics/src/test/java/test/javafx/scene/image/ImageView_cssMethods_Test.java b/modules/javafx.graphics/src/test/java/test/javafx/scene/image/ImageView_cssMethods_Test.java
index 7c3b4dde104..12f1f541484 100644
--- a/modules/javafx.graphics/src/test/java/test/javafx/scene/image/ImageView_cssMethods_Test.java
+++ b/modules/javafx.graphics/src/test/java/test/javafx/scene/image/ImageView_cssMethods_Test.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2023, 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
@@ -74,14 +74,16 @@ public static void configureImageLoaderFactory() {
@Parameters
public static Collection data() {
+ boolean smooth = ImageView.SMOOTH_DEFAULT;
+
return Arrays.asList(new Object[] {
- config(TEST_IMAGE_VIEW, "image", null,
- "-fx-image", TEST_IMAGE_URL1, IMAGE_COMPARATOR),
- config(TEST_IMAGE_VIEW, "image",
- TestImages.TEST_IMAGE_32x32,
- "-fx-image", TEST_IMAGE_URL2, IMAGE_COMPARATOR),
- config(TEST_IMAGE_VIEW, "translateX", 0.0,
- "-fx-translate-x", 10.0)
+ config(TEST_IMAGE_VIEW, "image", null, "-fx-image", TEST_IMAGE_URL1, IMAGE_COMPARATOR),
+ config(TEST_IMAGE_VIEW, "image", TestImages.TEST_IMAGE_32x32, "-fx-image", TEST_IMAGE_URL2, IMAGE_COMPARATOR),
+ config(TEST_IMAGE_VIEW, "translateX", 0.0, "-fx-translate-x", 10.0),
+ config(TEST_IMAGE_VIEW, "fitHeight", 0.0, "-fx-fit-height", 10.0),
+ config(TEST_IMAGE_VIEW, "fitWidth", 0.0, "-fx-fit-width", 10.0),
+ config(TEST_IMAGE_VIEW, "preserveRatio", false, "-fx-preserve-ratio", true),
+ config(TEST_IMAGE_VIEW, "smooth", smooth, "-fx-smooth", !smooth),
});
}