Browse Source

Ensure derived icons with the same size share their underlying image resource.

pull/188/head
weisj 4 years ago
parent
commit
8c300d251c
  1. 15
      property-loader/src/main/java/com/github/weisj/darklaf/icons/DarkSVGIcon.java
  2. 106
      property-loader/src/main/java/com/github/weisj/darklaf/icons/DerivableImageIcon.java
  3. 12
      property-loader/src/main/java/com/github/weisj/darklaf/icons/IconLoader.java
  4. 54
      property-loader/src/test/java/com/github/weisj/darklaf/icons/DerivableImageIconTest.java
  5. BIN
      property-loader/src/test/resources/com/github/weisj/darklaf/icons/image_icon.png
  6. 17
      utils/src/main/java/com/github/weisj/darklaf/util/LazyValue.java

15
property-loader/src/main/java/com/github/weisj/darklaf/icons/DarkSVGIcon.java

@ -101,12 +101,12 @@ public class DarkSVGIcon implements DerivableIcon<DarkSVGIcon>, RotateIcon, Seri
loaded = new AtomicBoolean(false);
}
protected DarkSVGIcon(final int width, final int height, final DarkSVGIcon icon) {
protected DarkSVGIcon(final int width, final int height, final DarkSVGIcon parent) {
this.size = new Dimension(width, height);
this.icon = icon.icon;
this.uri = icon.uri;
this.uriSupplier = icon.uriSupplier;
this.loaded = icon.loaded;
this.icon = parent.icon;
this.uri = parent.uri;
this.uriSupplier = parent.uriSupplier;
this.loaded = parent.loaded;
}
@Override
@ -174,15 +174,14 @@ public class DarkSVGIcon implements DerivableIcon<DarkSVGIcon>, RotateIcon, Seri
* If we get to here the issue was that the icon hasn't been patched because it isn't loaded as a themed
* svg icon.
*/
LOGGER.severe("Icon '" + getName() + "' that defines custom colors isn't loaded as themed icon.");
LOGGER.severe("Icon '" + getName(uri) + "' that defines custom colors isn't loaded as themed icon.");
return img;
}
throw e;
}
}
protected String getName() {
ensureURILoaded();
protected String getName(final URI uri) {
String name = uri.toASCIIString();
name = name.substring(Math.min(name.length() - 1, name.lastIndexOf('/') + 1));
return name;

106
property-loader/src/main/java/com/github/weisj/darklaf/icons/DerivableImageIcon.java

@ -32,17 +32,18 @@ import java.util.function.Supplier;
import javax.accessibility.*;
import javax.swing.*;
import com.github.weisj.darklaf.util.LazyValue;
public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Accessible {
private static final int DEFAULT_SCALING_MODE = Image.SCALE_SMOOTH;
private static final int DEFAULT_SCALING_MODE = Image.SCALE_DEFAULT;
private final int scalingMode;
private int width;
private int height;
private Supplier<Image> imageSupplier;
private Image original;
private Image img;
private final LazyValue<Image> original;
private final LazyImageValue image;
private String description;
private AccessibleContext accessibleContext;
@ -125,7 +126,8 @@ public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Ac
this.width = width;
this.height = height;
this.scalingMode = scalingMode;
this.imageSupplier = imageSupplier;
this.original = new LazyValue<>(imageSupplier);
this.image = new LazyImageValue(this);
}
/**
@ -220,10 +222,8 @@ public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Ac
this.width = width;
this.height = height;
this.scalingMode = scalingMode;
this.original = img;
if (img != null && img.getWidth(null) == width && img.getHeight(null) == height) {
this.img = img;
}
this.original = new LazyValue<>(img);
this.image = new LazyImageValue(this);
}
protected DerivableImageIcon(final DerivableImageIcon parent, final int width, final int height) {
@ -232,16 +232,7 @@ public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Ac
this.scalingMode = parent.scalingMode;
this.original = parent.original;
this.description = parent.description;
this.imageSupplier = parent.imageSupplier;
if (this.original != null
&& this.original.getWidth(null) == width
&& this.original.getHeight(null) == height) {
this.img = this.original;
} else if (parent.img != null
&& parent.img.getWidth(null) == width
&& parent.img.getHeight(null) == height) {
this.img = parent.img;
}
this.image = parent.image.derive(this);
}
@Override
@ -249,31 +240,9 @@ public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Ac
return new DerivableImageIcon(this, width, height);
}
protected void ensureOriginalLoaded() {
if (original == null && imageSupplier != null) {
original = imageSupplier.get();
imageSupplier = null;
}
}
protected void ensureLoaded() {
ensureOriginalLoaded();
if (original != null && (width < 0 || height < 0)) {
if (width < 0) width = original.getWidth(null);
if (height < 0) height = original.getHeight(null);
}
if (img == null && original != null && width > 0 && height > 0) {
if (original.getWidth(null) != width || original.getHeight(null) != height) {
img = original.getScaledInstance(width, height, scalingMode);
} else {
img = original;
}
}
}
@Override
public void paintIcon(final Component c, final Graphics g, final int x, final int y) {
ensureLoaded();
Image img = image.get();
if (img != null) {
g.drawImage(img, x, y, width, height, null);
}
@ -285,19 +254,32 @@ public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Ac
* @return the image.
*/
public Image getImage() {
ensureLoaded();
return image.get();
}
protected Image getOriginal() {
Image img = original.get();
calculateSize();
return img;
}
private void calculateSize() {
Image originalImage = original.get();
if (originalImage != null && (width < 0 || height < 0)) {
if (width < 0) width = originalImage.getWidth(null);
if (height < 0) height = originalImage.getHeight(null);
}
}
@Override
public int getIconWidth() {
if (width < 0) ensureLoaded();
if (width < 0) calculateSize();
return width;
}
@Override
public int getIconHeight() {
if (height < 0) ensureLoaded();
if (height < 0) calculateSize();
return height;
}
@ -392,4 +374,38 @@ public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Ac
return icon.getIconHeight();
}
}
protected static class LazyImageValue extends LazyValue<Image> {
private final DerivableImageIcon icon;
public LazyImageValue(final DerivableImageIcon icon) {
super((Image) null);
this.icon = icon;
}
public LazyImageValue derive(final DerivableImageIcon icon) {
if (this.icon.width == icon.width && this.icon.height == icon.height) {
// Make sure all icons with the same dimension share one image.
return this;
}
return new LazyImageValue(icon);
}
@Override
protected Image load() {
Image originalImage = icon.getOriginal();
int width = icon.getIconWidth();
int height = icon.getIconHeight();
if (originalImage != null && width > 0 && height > 0) {
if (originalImage.getWidth(null) != width
|| originalImage.getHeight(null) != height) {
return originalImage.getScaledInstance(width, height, icon.scalingMode);
} else {
return originalImage;
}
}
return null;
}
}
}

12
property-loader/src/main/java/com/github/weisj/darklaf/icons/IconLoader.java

@ -263,8 +263,6 @@ public final class IconLoader {
}
// Icon not found or caching is disabled.
key.w = w; // Restore key.
if (isSVGIcon(path)) {
Icon icon = loadSVGIcon(path, w, h, themed);
cache(iconMap, key, icon);
@ -278,15 +276,16 @@ public final class IconLoader {
private Icon getWildcardIcon(final Map<IconKey, Icon> iconMap,
final IconKey iconKey, final int w, final int h) {
iconKey.w = -1;
iconKey.isWildcardEnabled = true;
Icon icon = iconMap.get(iconKey);
if (icon instanceof DerivableIcon) {
@SuppressWarnings("unchecked")
Icon derived = ((DerivableIcon<Icon>) icon).derive(w, h);
iconKey.w = w;
iconKey.isWildcardEnabled = false;
cache(iconMap, iconKey, derived);
return derived;
}
iconKey.isWildcardEnabled = false;
return null;
}
@ -374,7 +373,7 @@ public final class IconLoader {
* @return the ImageIcon.
*/
ImageIcon createImageIcon(final String path, final String description) {
java.net.URL imgURL = getResource(path);
URL imgURL = getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL, description);
} else {
@ -422,6 +421,7 @@ public final class IconLoader {
final String path;
int w;
int h;
boolean isWildcardEnabled;
private IconKey(final String path, final int w, final int h) {
this.path = path;
@ -441,7 +441,7 @@ public final class IconLoader {
IconKey iconKey = (IconKey) o;
if (iconKey.w == -1 || iconKey.h == -1 || this.h == -1 || this.w == -1) {
if (iconKey.isWildcardEnabled || this.isWildcardEnabled) {
// Math any size.
return Objects.equals(path, iconKey.path);
}

54
property-loader/src/test/java/com/github/weisj/darklaf/icons/DerivableImageIconTest.java

@ -0,0 +1,54 @@
/*
* MIT License
*
* Copyright (c) 2020 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package com.github.weisj.darklaf.icons;
import java.awt.*;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class DerivableImageIconTest {
@Test
public void testCache() {
IconLoader loader = IconLoader.get(DerivableImageIconTest.class);
DerivableImageIcon icon = (DerivableImageIcon) loader.getIcon("image_icon.png");
Set<Image> imageSet = new HashSet<>();
for (int i = 0; i < 100; i++) {
Image img = ((DerivableImageIcon) loader.getIcon("image_icon.png", 100, 100)).getImage();
imageSet.add(img);
}
Assertions.assertEquals(1, imageSet.size());
imageSet.clear();
icon = icon.derive(50, 50);
for (int i = 0; i < 100; i++) {
imageSet.add(icon.derive(50, 50).getImage());
}
Assertions.assertEquals(1, imageSet.size());
}
}

BIN
property-loader/src/test/resources/com/github/weisj/darklaf/icons/image_icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 B

17
utils/src/main/java/com/github/weisj/darklaf/util/LazyValue.java

@ -31,8 +31,11 @@ public class LazyValue<T> {
private Supplier<T> supplier;
private T value;
public LazyValue(final Supplier<T> supplier) {
public LazyValue(final T value) {
this.value = value;
}
public LazyValue(final Supplier<T> supplier) {
this.supplier = supplier;
}
@ -40,11 +43,17 @@ public class LazyValue<T> {
return supplier == null;
}
public T get() {
if (value == null && supplier != null) {
value = supplier.get();
protected T load() {
if (supplier != null) {
T obj = supplier.get();
supplier = null;
return obj;
}
return value;
}
public T get() {
if (value == null) value = load();
return value;
}
}

Loading…
Cancel
Save