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); 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.size = new Dimension(width, height);
this.icon = icon.icon; this.icon = parent.icon;
this.uri = icon.uri; this.uri = parent.uri;
this.uriSupplier = icon.uriSupplier; this.uriSupplier = parent.uriSupplier;
this.loaded = icon.loaded; this.loaded = parent.loaded;
} }
@Override @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 * 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. * 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; return img;
} }
throw e; throw e;
} }
} }
protected String getName() { protected String getName(final URI uri) {
ensureURILoaded();
String name = uri.toASCIIString(); String name = uri.toASCIIString();
name = name.substring(Math.min(name.length() - 1, name.lastIndexOf('/') + 1)); name = name.substring(Math.min(name.length() - 1, name.lastIndexOf('/') + 1));
return name; 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.accessibility.*;
import javax.swing.*; import javax.swing.*;
import com.github.weisj.darklaf.util.LazyValue;
public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Accessible { 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 final int scalingMode;
private int width; private int width;
private int height; private int height;
private Supplier<Image> imageSupplier; private final LazyValue<Image> original;
private Image original; private final LazyImageValue image;
private Image img;
private String description; private String description;
private AccessibleContext accessibleContext; private AccessibleContext accessibleContext;
@ -125,7 +126,8 @@ public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Ac
this.width = width; this.width = width;
this.height = height; this.height = height;
this.scalingMode = scalingMode; 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.width = width;
this.height = height; this.height = height;
this.scalingMode = scalingMode; this.scalingMode = scalingMode;
this.original = img; this.original = new LazyValue<>(img);
if (img != null && img.getWidth(null) == width && img.getHeight(null) == height) { this.image = new LazyImageValue(this);
this.img = img;
}
} }
protected DerivableImageIcon(final DerivableImageIcon parent, final int width, final int height) { 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.scalingMode = parent.scalingMode;
this.original = parent.original; this.original = parent.original;
this.description = parent.description; this.description = parent.description;
this.imageSupplier = parent.imageSupplier; this.image = parent.image.derive(this);
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;
}
} }
@Override @Override
@ -249,31 +240,9 @@ public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Ac
return new DerivableImageIcon(this, width, height); 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 @Override
public void paintIcon(final Component c, final Graphics g, final int x, final int y) { public void paintIcon(final Component c, final Graphics g, final int x, final int y) {
ensureLoaded(); Image img = image.get();
if (img != null) { if (img != null) {
g.drawImage(img, x, y, width, height, null); g.drawImage(img, x, y, width, height, null);
} }
@ -285,19 +254,32 @@ public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Ac
* @return the image. * @return the image.
*/ */
public Image getImage() { public Image getImage() {
ensureLoaded(); return image.get();
}
protected Image getOriginal() {
Image img = original.get();
calculateSize();
return img; 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 @Override
public int getIconWidth() { public int getIconWidth() {
if (width < 0) ensureLoaded(); if (width < 0) calculateSize();
return width; return width;
} }
@Override @Override
public int getIconHeight() { public int getIconHeight() {
if (height < 0) ensureLoaded(); if (height < 0) calculateSize();
return height; return height;
} }
@ -392,4 +374,38 @@ public class DerivableImageIcon implements DerivableIcon<DerivableImageIcon>, Ac
return icon.getIconHeight(); 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. // Icon not found or caching is disabled.
key.w = w; // Restore key.
if (isSVGIcon(path)) { if (isSVGIcon(path)) {
Icon icon = loadSVGIcon(path, w, h, themed); Icon icon = loadSVGIcon(path, w, h, themed);
cache(iconMap, key, icon); cache(iconMap, key, icon);
@ -278,15 +276,16 @@ public final class IconLoader {
private Icon getWildcardIcon(final Map<IconKey, Icon> iconMap, private Icon getWildcardIcon(final Map<IconKey, Icon> iconMap,
final IconKey iconKey, final int w, final int h) { final IconKey iconKey, final int w, final int h) {
iconKey.w = -1; iconKey.isWildcardEnabled = true;
Icon icon = iconMap.get(iconKey); Icon icon = iconMap.get(iconKey);
if (icon instanceof DerivableIcon) { if (icon instanceof DerivableIcon) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Icon derived = ((DerivableIcon<Icon>) icon).derive(w, h); Icon derived = ((DerivableIcon<Icon>) icon).derive(w, h);
iconKey.w = w; iconKey.isWildcardEnabled = false;
cache(iconMap, iconKey, derived); cache(iconMap, iconKey, derived);
return derived; return derived;
} }
iconKey.isWildcardEnabled = false;
return null; return null;
} }
@ -374,7 +373,7 @@ public final class IconLoader {
* @return the ImageIcon. * @return the ImageIcon.
*/ */
ImageIcon createImageIcon(final String path, final String description) { ImageIcon createImageIcon(final String path, final String description) {
java.net.URL imgURL = getResource(path); URL imgURL = getResource(path);
if (imgURL != null) { if (imgURL != null) {
return new ImageIcon(imgURL, description); return new ImageIcon(imgURL, description);
} else { } else {
@ -422,6 +421,7 @@ public final class IconLoader {
final String path; final String path;
int w; int w;
int h; int h;
boolean isWildcardEnabled;
private IconKey(final String path, final int w, final int h) { private IconKey(final String path, final int w, final int h) {
this.path = path; this.path = path;
@ -441,7 +441,7 @@ public final class IconLoader {
IconKey iconKey = (IconKey) o; 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. // Math any size.
return Objects.equals(path, iconKey.path); 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 Supplier<T> supplier;
private T value; 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; this.supplier = supplier;
} }
@ -40,11 +43,17 @@ public class LazyValue<T> {
return supplier == null; return supplier == null;
} }
public T get() { protected T load() {
if (value == null && supplier != null) { if (supplier != null) {
value = supplier.get(); T obj = supplier.get();
supplier = null; supplier = null;
return obj;
} }
return value; return value;
} }
public T get() {
if (value == null) value = load();
return value;
}
} }

Loading…
Cancel
Save