From eab8dd34a03f215106bc1beb60eed206bd2a685f Mon Sep 17 00:00:00 2001 From: Anton Tarasov Date: Fri, 8 Jun 2018 12:25:40 +0300 Subject: [PATCH] Fix IconScaleTest; Add UIUtil.createImage(ScaleContext, ...) --- .../com/intellij/util/ui/IconScaleTest.java | 28 ++++++++++--------- .../com/intellij/openapi/util/IconLoader.java | 26 ++++++++++++----- .../com/intellij/util/JBHiDPIScaledImage.java | 21 +++++++++----- .../src/com/intellij/util/RetinaImage.java | 6 ++++ .../util/src/com/intellij/util/ui/UIUtil.java | 16 +++++++++-- 5 files changed, 68 insertions(+), 29 deletions(-) diff --git a/platform/platform-tests/testSrc/com/intellij/util/ui/IconScaleTest.java b/platform/platform-tests/testSrc/com/intellij/util/ui/IconScaleTest.java index fea03cd00ded..1d6021e0659c 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/ui/IconScaleTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/ui/IconScaleTest.java @@ -94,29 +94,31 @@ public class IconScaleTest extends BareTestFixtureTestCase { test(new RowIcon(new CachedImageIcon(new File(getIconPath()).toURI().toURL())), BaseScaleContext.create(ctx)); } - private static void test(Icon icon, BaseScaleContext ctx) { - ((ScaleContextAware)icon).updateScaleContext(ctx); + private static void test(Icon icon, BaseScaleContext bctx) { + ((ScaleContextAware)icon).updateScaleContext(bctx); + + ScaleContext ctx = ScaleContext.create(bctx); int usrSize = (int)Math.round(ICON_BASE_SIZE * ctx.getScale(USR_SCALE)); int devSize = (int)Math.round(usrSize * ctx.getScale(SYS_SCALE)); - assertEquals("unexpected icon user width", usrSize, icon.getIconWidth()); - assertEquals("unexpected icon user height", usrSize, icon.getIconHeight()); - assertEquals("unexpected icon real width", devSize, ImageUtil.getRealWidth(IconUtil.toImage(icon))); - assertEquals("unexpected icon real height", devSize, ImageUtil.getRealHeight(IconUtil.toImage(icon))); + assertEquals("unexpected icon user width " + bctx, usrSize, icon.getIconWidth()); + assertEquals("unexpected icon user height " + bctx, usrSize, icon.getIconHeight()); + assertEquals("unexpected icon real width " + bctx, devSize, ImageUtil.getRealWidth(IconUtil.toImage(icon, ctx))); + assertEquals("unexpected icon real height " + bctx, devSize, ImageUtil.getRealHeight(IconUtil.toImage(icon, ctx))); Icon scaledIcon = IconUtil.scale(icon, null, ICON_OBJ_SCALE); - assertNotSame("scaled instance of the icon", icon, scaledIcon); - assertEquals("ScaleContext of the original icon changed", ctx, ((ScaleContextAware)icon).getScaleContext()); + assertNotSame("scaled instance of the icon " + bctx, icon, scaledIcon); + assertEquals("ScaleContext of the original icon changed " + bctx, bctx, ((ScaleContextAware)icon).getScaleContext()); int scaledUsrSize = Math.round(usrSize * ICON_OBJ_SCALE); int scaledDevSize = Math.round(devSize * ICON_OBJ_SCALE); - assertEquals("unexpected scaled icon user width", scaledUsrSize, scaledIcon.getIconWidth()); - assertEquals("unexpected scaled icon user height", scaledUsrSize, scaledIcon.getIconHeight()); - assertEquals("unexpected scaled icon real width", scaledDevSize, ImageUtil.getRealWidth(IconUtil.toImage(scaledIcon))); - assertEquals("unexpected scaled icon real height", scaledDevSize, ImageUtil.getRealHeight(IconUtil.toImage(scaledIcon))); + assertEquals("unexpected scaled icon user width " + bctx, scaledUsrSize, scaledIcon.getIconWidth()); + assertEquals("unexpected scaled icon user height " + bctx, scaledUsrSize, scaledIcon.getIconHeight()); + assertEquals("unexpected scaled icon real width " + bctx, scaledDevSize, ImageUtil.getRealWidth(IconUtil.toImage(scaledIcon, ctx))); + assertEquals("unexpected scaled icon real height " + bctx, scaledDevSize, ImageUtil.getRealHeight(IconUtil.toImage(scaledIcon, ctx))); // Additionally check that the original image hasn't changed after scaling Pair pair = createImageAndGraphics(ctx.getScale(SYS_SCALE), icon.getIconWidth(), icon.getIconHeight()); @@ -125,7 +127,7 @@ public class IconScaleTest extends BareTestFixtureTestCase { icon.paintIcon(null, g2d, 0, 0); - BufferedImage goldImage = loadImage(getIconPath(), ScaleContext.create(ctx)); + BufferedImage goldImage = loadImage(getIconPath(), ctx); ImageComparator.compareAndAssert( new ImageComparator.AASmootherComparator(0.1, 0.1, new Color(0, 0, 0, 0)), goldImage, iconImage, null); diff --git a/platform/util/src/com/intellij/openapi/util/IconLoader.java b/platform/util/src/com/intellij/openapi/util/IconLoader.java index 6ab090d097c8..b44e9903de26 100644 --- a/platform/util/src/com/intellij/openapi/util/IconLoader.java +++ b/platform/util/src/com/intellij/openapi/util/IconLoader.java @@ -5,6 +5,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import com.intellij.reference.SoftReference; import com.intellij.ui.RetrievableIcon; +import com.intellij.ui.paint.PaintUtil.RoundingMode; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.ImageLoader; import com.intellij.util.ReflectionUtil; @@ -291,6 +292,9 @@ public final class IconLoader { @Nullable public static Image toImage(@NotNull Icon icon, @Nullable ScaleContext ctx) { + if (icon instanceof RetrievableIcon) { + icon = ((RetrievableIcon)icon).retrieveIcon(); + } if (icon instanceof CachedImageIcon) { icon = ((CachedImageIcon)icon).getRealIcon(ctx); } @@ -298,13 +302,21 @@ public final class IconLoader { return ((ImageIcon)icon).getImage(); } else { - final int w = icon.getIconWidth(); - final int h = icon.getIconHeight(); - final BufferedImage image = GraphicsEnvironment.getLocalGraphicsEnvironment() - .getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(w, h, Transparency.TRANSLUCENT); - final Graphics2D g = image.createGraphics(); - icon.paintIcon(null, g, 0, 0); - g.dispose(); + BufferedImage image; + if (GraphicsEnvironment.isHeadless()) { // for testing purpose + image = UIUtil.createImage(ctx, icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB, RoundingMode.FLOOR); + } else { + // [tav] todo: match the screen with the provided ctx + image = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration() + .createCompatibleImage(icon.getIconWidth(), icon.getIconHeight(), Transparency.TRANSLUCENT); + } + Graphics2D g = image.createGraphics(); + try { + icon.paintIcon(null, g, 0, 0); + } finally { + g.dispose(); + } return image; } } diff --git a/platform/util/src/com/intellij/util/JBHiDPIScaledImage.java b/platform/util/src/com/intellij/util/JBHiDPIScaledImage.java index 2194fb74dce9..eb0055beef3d 100644 --- a/platform/util/src/com/intellij/util/JBHiDPIScaledImage.java +++ b/platform/util/src/com/intellij/util/JBHiDPIScaledImage.java @@ -86,6 +86,13 @@ public class JBHiDPIScaledImage extends BufferedImage { this(gc, (double)width, (double)height, type); } + /** + * @see #JBHiDPIScaledImage(GraphicsConfiguration, double, double, int) + */ + public JBHiDPIScaledImage(@Nullable JBUI.ScaleContext ctx, double width, double height, int type, @NotNull RoundingMode rm) { + this(JBUI.sysScale(ctx), width, height, type, rm); + } + /** * Creates a scaled HiDPI-aware BufferedImage, targeting the graphics config. * @@ -95,11 +102,7 @@ public class JBHiDPIScaledImage extends BufferedImage { * @param type the type */ public JBHiDPIScaledImage(@Nullable GraphicsConfiguration gc, double width, double height, int type) { - super((int)(width * JBUI.sysScale(gc)), (int)(height * JBUI.sysScale(gc)), type); - myImage = null; - myUserWidth = width; - myUserHeight = height; - myScale = JBUI.sysScale(gc); + this(gc, width, height, type, RoundingMode.FLOOR); } /** @@ -112,11 +115,15 @@ public class JBHiDPIScaledImage extends BufferedImage { * @param type the type */ public JBHiDPIScaledImage(@Nullable GraphicsConfiguration gc, double width, double height, int type, @NotNull RoundingMode rm) { - super(rm.round(width * JBUI.sysScale(gc)), rm.round(height * JBUI.sysScale(gc)), type); + this(JBUI.sysScale(gc), width, height, type, rm); + } + + private JBHiDPIScaledImage(double scale, double width, double height, int type, @NotNull RoundingMode rm) { + super(rm.round(width * scale), rm.round(height * scale), type); myImage = null; myUserWidth = width; myUserHeight = height; - myScale = JBUI.sysScale(gc); + myScale = scale; } /** diff --git a/platform/util/src/com/intellij/util/RetinaImage.java b/platform/util/src/com/intellij/util/RetinaImage.java index 09c01e77f34b..45e08676731b 100644 --- a/platform/util/src/com/intellij/util/RetinaImage.java +++ b/platform/util/src/com/intellij/util/RetinaImage.java @@ -2,6 +2,7 @@ package com.intellij.util; import com.intellij.ui.paint.PaintUtil.RoundingMode; +import com.intellij.util.ui.JBUI.ScaleContext; import org.jetbrains.annotations.NotNull; import java.awt.*; @@ -71,6 +72,11 @@ public class RetinaImage { // [tav] todo: create HiDPIImage class return new JBHiDPIScaledImage(gc, width, height, type, rm); } + @NotNull + public static BufferedImage create(ScaleContext ctx, double width, double height, int type, RoundingMode rm) { + return new JBHiDPIScaledImage(ctx, width, height, type, rm); + } + /** @deprecated Apple JRE is no longer supported (to be removed in IDEA 2019) */ public static boolean isAppleHiDPIScaledImage(@SuppressWarnings("unused") Image image) { return false; diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 2ee9a93d8cfe..60051146a2da 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -13,7 +13,7 @@ import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.ui.*; import com.intellij.ui.mac.foundation.Foundation; import com.intellij.ui.paint.LinePainter2D; -import com.intellij.ui.paint.PaintUtil; +import com.intellij.ui.paint.PaintUtil.RoundingMode; import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.JBIterable; @@ -2104,7 +2104,7 @@ public class UIUtil { * @return a HiDPI-aware BufferedImage in the graphics scale */ @NotNull - public static BufferedImage createImage(GraphicsConfiguration gc, double width, double height, int type, PaintUtil.RoundingMode rm) { + public static BufferedImage createImage(GraphicsConfiguration gc, double width, double height, int type, RoundingMode rm) { if (isJreHiDPI(gc)) { return RetinaImage.create(gc, width, height, type, rm); } @@ -2112,6 +2112,18 @@ public class UIUtil { return new BufferedImage(rm.round(width), rm.round(height), type); } + /** + * @see #createImage(GraphicsConfiguration, double, double, int, RoundingMode) + */ + @NotNull + public static BufferedImage createImage(ScaleContext ctx, double width, double height, int type, RoundingMode rm) { + if (isJreHiDPI(ctx)) { + return RetinaImage.create(ctx, width, height, type, rm); + } + //noinspection UndesirableClassUsage + return new BufferedImage(rm.round(width), rm.round(height), type); + } + /** * Creates a HiDPI-aware BufferedImage in the graphics device scale. *