Commit a2a1f97a authored by Anton Tarasov's avatar Anton Tarasov
Browse files

CachedImageIcon.scale(value) should be immutable

- it should return new icon instance for value!=1 and it's allowed to return "this" for value==1
parent a3e86c5a
Branches unavailable Tags unavailable
No related merge requests found
Showing with 151 additions and 5 deletions
+151 -5
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<title>abstractClass</title>
<g>
<path d="M11,1.68261a6.93358,6.93358,0,0,0-6,0V14.31737a6.93358,6.93358,0,0,0,6,0V1.68261Z" fill="#40b6e0" opacity="0.5" style="isolation: isolate"/>
<path d="M10.616,9.98144l-0.5407-.55337a2.47758,2.47758,0,0,1-1.88411.78046A2.12355,2.12355,0,0,1,6.16382,8V7.98339A2.145,2.145,0,0,1,8.22873,5.76118l0.0204-.00065a2.6174,2.6174,0,0,1,1.82321.71283l0.51116-.55467A3.13348,3.13348,0,0,0,8.2804,5H8.09859A3.02986,3.02986,0,0,0,5.00064,7.96019L5,8V8.01635A2.994,2.994,0,0,0,8.00238,11H8.256A3.12367,3.12367,0,0,0,10.616,9.98144Z" fill="#231f20" opacity="0.6" style="isolation: isolate"/>
<path d="M4,2.26A6.99125,6.99125,0,0,0,4,13.74V2.26Z" fill="#9aa7b0" opacity="0.6" style="isolation: isolate"/>
<path d="M12,2.26V13.74A6.99125,6.99125,0,0,0,12,2.26Z" fill="#9aa7b0" opacity="0.6" style="isolation: isolate"/>
</g>
</svg>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<title>abstractClass@2x</title>
<g>
<path d="M22,3.36522a13.86717,13.86717,0,0,0-12,0V28.63475a13.86717,13.86717,0,0,0,12,0V3.36522Z" fill="#40b6e0" opacity="0.5" style="isolation: isolate"/>
<path d="M21.23186,19.96312l-1.0814-1.10674a4.95515,4.95515,0,0,1-3.76821,1.56092,4.2471,4.2471,0,0,1-4.05469-4.41708V15.967a4.28989,4.28989,0,0,1,4.12959-4.44441l0.041-.00131A5.2348,5.2348,0,0,1,20.14461,12.947l1.02231-1.10934a6.267,6.267,0,0,0-4.6062-1.8374H16.1971a6.05971,6.05971,0,0,0-6.19589,5.9204l-0.00129.0796V16.033a5.9881,5.9881,0,0,0,6.00476,5.96729h0.50721A6.24735,6.24735,0,0,0,21.23186,19.96312Z" fill="#231f20" opacity="0.6" style="isolation: isolate"/>
<path d="M8,4.52A13.9825,13.9825,0,0,0,8,27.48V4.52Z" fill="#9aa7b0" opacity="0.6" style="isolation: isolate"/>
<path d="M24,4.52V27.48A13.9825,13.9825,0,0,0,24,4.52Z" fill="#9aa7b0" opacity="0.6" style="isolation: isolate"/>
</g>
</svg>
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.util.ui;
import com.intellij.openapi.util.IconLoader.CachedImageIcon;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.registry.RegistryValue;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.util.IconUtil;
import com.intellij.util.ui.JBUI.ScaleContext;
import com.intellij.util.ui.paint.AbstractPainter2DTest;
import com.intellij.util.ui.paint.PaintUtilTest;
import junit.framework.TestCase;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import javax.swing.*;
import java.io.File;
import java.net.MalformedURLException;
import static com.intellij.util.ui.JBUI.ScaleType.SYS_SCALE;
/**
* Tests that {@link CachedImageIcon#scale(float)} doesn't break the contract and scales correctly.
*
* @author tav
*/
public class IconScaleTest {
private static boolean initialSvgProp;
@Before
public void setState() {
RegistryValue rv = Registry.get("ide.svg.icon");
initialSvgProp = rv.asBoolean();
rv.setValue(true);
AbstractPainter2DTest.ScaleState.set();
}
@After
public void restoreState() {
Registry.get("ide.svg.icon").setValue(initialSvgProp);
AbstractPainter2DTest.ScaleState.restore();
}
@Test
public void test() throws MalformedURLException {
Assume.assumeFalse("Linux doesn't support JRE-HiDPI yet", SystemInfo.isLinux);
test(1.0);
test(2.0);
test(2.5);
}
public void test(double sysScale) throws MalformedURLException {
final int BASE_SIZE = 16;
final float ICON_SCALE = 1.75f;
PaintUtilTest.overrideJreHiDPIEnabled(true);
JBUI.setUserScaleFactor(1);
CachedImageIcon icon = new CachedImageIcon(new File(getIconPath()).toURI().toURL());
icon.updateScale(SYS_SCALE.of(sysScale));
ScaleContext originalCtx = icon.getScaleContext().copy();
TestCase.assertEquals("unexpected icon user width", BASE_SIZE, icon.getIconWidth());
TestCase.assertEquals("unexpected icon user height", BASE_SIZE, icon.getIconHeight());
TestCase.assertEquals("unexpected icon real width", 0,
Double.compare(BASE_SIZE * sysScale, ImageUtil.getRealWidth(IconUtil.toImage(icon))));
TestCase.assertEquals("unexpected icon real height", 0,
Double.compare(BASE_SIZE * sysScale, ImageUtil.getRealHeight(IconUtil.toImage(icon))));
Icon scaledIcon = icon.scale(ICON_SCALE);
TestCase.assertFalse("new instance of the icon is expected", icon == scaledIcon);
TestCase.assertEquals("ScaleContext of the original icon changed", originalCtx, icon.getScaleContext());
TestCase.assertEquals("unexpected icon user width", 0,
Double.compare(BASE_SIZE * ICON_SCALE, scaledIcon.getIconWidth()));
TestCase.assertEquals("unexpected icon user height", 0,
Double.compare(BASE_SIZE * ICON_SCALE, scaledIcon.getIconHeight()));
TestCase.assertEquals("unexpected icon real width", 0,
Double.compare(BASE_SIZE * ICON_SCALE * sysScale, ImageUtil.getRealWidth(IconUtil.toImage(scaledIcon))));
TestCase.assertEquals("unexpected icon real height", 0,
Double.compare(BASE_SIZE * ICON_SCALE * sysScale, ImageUtil.getRealHeight(IconUtil.toImage(scaledIcon))));
}
private String getIconPath() {
return PlatformTestUtil.getPlatformTestDataPath() + "ui/abstractClass.svg";
}
}
......@@ -567,9 +567,10 @@ public final class IconLoader {
* Retrieves the orig icon scaled by the provided scale.
*/
ImageIcon getOrScaleIcon(final float scale) {
updateScale(OBJ_SCALE.of(scale));
final ScaleContext ctx = (scale == 1 ? getScaleContext() : (ScaleContext)getScaleContext().copy()); // not modifying this scale context
if (scale != 1) ctx.update(OBJ_SCALE.of(scale));
ImageIcon icon = SoftReference.dereference(scaledIconsCache.get(getScale(PIX_SCALE)));
ImageIcon icon = SoftReference.dereference(scaledIconsCache.get(ctx.getScale(PIX_SCALE)));
if (icon != null) {
return icon;
}
......@@ -578,17 +579,17 @@ public final class IconLoader {
image = doWithTmpRegValue("ide.svg.icon", true, new Callable<Image>() {
@Override
public Image call() {
return loadFromUrl(getScaleContext());
return loadFromUrl(ctx);
}
});
}
else {
image = loadFromUrl(getScaleContext());
image = loadFromUrl(ctx);
}
icon = checkIcon(image, myUrl);
if (icon != null && icon.getIconWidth() * icon.getIconHeight() * 4 < ImageLoader.CACHED_IMAGE_MAX_SIZE) {
scaledIconsCache.put(getScale(PIX_SCALE), new SoftReference<ImageIcon>(icon));
scaledIconsCache.put(ctx.getScale(PIX_SCALE), new SoftReference<ImageIcon>(icon));
}
return icon;
}
......
......@@ -743,6 +743,13 @@ public class JBUI {
private BaseScaleContext() {
}
/**
* Creates a context with all scale factors set to 1.
*/
public static BaseScaleContext createIdentity() {
return create(USR_SCALE.of(1));
}
/**
* Creates a context with the provided scale factors (system scale is ignored)
*/
......@@ -876,6 +883,18 @@ public class JBUI {
}
return true;
}
public <T extends BaseScaleContext> T copy() {
BaseScaleContext ctx = createIdentity();
ctx.updateAll(this);
//noinspection unchecked
return (T)ctx;
}
@Override
public String toString() {
return usrScale + ", " + objScale + ", " + pixScale;
}
}
/**
......@@ -1037,6 +1056,19 @@ public class JBUI {
compRef.clear();
}
}
@Override
public <T extends BaseScaleContext> T copy() {
ScaleContext ctx = createIdentity();
ctx.updateAll(this);
//noinspection unchecked
return (T)ctx;
}
@Override
public String toString() {
return usrScale + ", " + sysScale + ", " + objScale + ", " + pixScale;
}
}
/**
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment