mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-06 06:21:16 +07:00
IDEA-180409 initial support for fractional scale HiDPI
This commit is contained in:
@@ -86,10 +86,10 @@ public class IconUtil {
|
||||
int imageWidth = ImageUtil.getRealWidth(image);
|
||||
int imageHeight = ImageUtil.getRealHeight(image);
|
||||
|
||||
final int w = Math.min(imageWidth, maxWidth);
|
||||
final int h = Math.min(imageHeight, maxHeight);
|
||||
maxWidth = maxWidth == Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)ceil(maxWidth * scale);
|
||||
maxHeight = maxHeight == Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)ceil(maxHeight * scale);
|
||||
final int w = Math.min(imageWidth, maxWidth);
|
||||
final int h = Math.min(imageHeight, maxHeight);
|
||||
|
||||
final BufferedImage img = UIUtil.createImage(g, w, h, Transparency.TRANSLUCENT);
|
||||
final int offX = imageWidth > maxWidth ? (imageWidth - maxWidth) / 2 : 0;
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
package com.intellij.openapi.ui.impl;
|
||||
|
||||
import com.intellij.util.IconUtil;
|
||||
import com.intellij.util.ui.ImageUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.JBUI.ScaleContext;
|
||||
import com.intellij.util.ui.JBUI.ScaleContextSupport;
|
||||
import com.intellij.util.ui.JBUI.ScaleContextAware;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -107,25 +110,51 @@ public class ShadowPainter extends ScaleContextSupport<ScaleContext> {
|
||||
|
||||
myTopLeft.paintIcon(c, g, x, y);
|
||||
myTopRight.paintIcon(c, g, x + width - myTopRight.getIconWidth(), y);
|
||||
myBottomRight.paintIcon(c, g, x + width - myBottomRight.getIconWidth(), y + height - myBottomRight.getIconHeight());
|
||||
myBottomLeft.paintIcon(c, g, x, y + height - myBottomLeft.getIconHeight());
|
||||
myBottomRight.paintIcon(c, g, x + width - myBottomRight.getIconWidth(), y + height - myBottomRight.getIconHeight());
|
||||
|
||||
for (int _x = myTopLeft.getIconWidth(); _x < width - myTopRight.getIconWidth(); _x++) {
|
||||
myCroppedTop.paintIcon(c, g, _x + x, y);
|
||||
}
|
||||
for (int _x = myBottomLeft.getIconWidth(); _x < width - myBottomLeft.getIconWidth(); _x++) {
|
||||
myCroppedBottom.paintIcon(c, g, _x + x, y + height - bottomSize);
|
||||
}
|
||||
for (int _y = myTopLeft.getIconHeight(); _y < height - myBottomLeft.getIconHeight(); _y++) {
|
||||
myCroppedLeft.paintIcon(c, g, x, _y + y);
|
||||
}
|
||||
for (int _y = myTopRight.getIconHeight(); _y < height - myBottomRight.getIconHeight(); _y++) {
|
||||
myCroppedRight.paintIcon(c, g, x + width - rightSize, _y + y);
|
||||
}
|
||||
fill(g, myCroppedTop, x, y, myTopLeft.getIconWidth(), width - myTopRight.getIconWidth(), true);
|
||||
fill(g, myCroppedBottom, x, y + height - bottomSize, myBottomLeft.getIconWidth(), width - myBottomRight.getIconWidth(), true);
|
||||
fill(g, myCroppedLeft, x, y, myTopLeft.getIconHeight(), height - myBottomLeft.getIconHeight(), false);
|
||||
fill(g, myCroppedRight, x + width - rightSize, y, myTopRight.getIconHeight(), height - myBottomRight.getIconHeight(), false);
|
||||
|
||||
if (myBorderColor != null) {
|
||||
g.setColor(myBorderColor);
|
||||
g.drawRect(x + leftSize - 1, y + topSize - 1, width - leftSize - rightSize + 1, height - topSize - bottomSize + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void fill(Graphics g, Icon pattern, int x, int y, int from, int to, boolean horizontally) {
|
||||
double scale = JBUI.sysScale((Graphics2D)g);
|
||||
if (UIUtil.isJreHiDPIEnabled() && Math.ceil(scale) > scale) {
|
||||
// Direct painting for fractional scale
|
||||
BufferedImage img = ImageUtil.toBufferedImage(IconUtil.toImage(pattern));
|
||||
int patternSize = horizontally ? img.getWidth() : img.getHeight();
|
||||
Graphics2D g2d = (Graphics2D)g.create();
|
||||
try {
|
||||
g2d.scale(1 / scale, 1 / scale);
|
||||
g2d.translate(x * scale, y * scale);
|
||||
for (int at = (int)Math.floor(from * scale); at < to * scale; at += patternSize) {
|
||||
if (horizontally) {
|
||||
g2d.drawImage(img, at, 0, null);
|
||||
}
|
||||
else {
|
||||
g2d.drawImage(img, 0, at, null);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
g2d.dispose();
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int at = from; at < to; at++) {
|
||||
if (horizontally) {
|
||||
pattern.paintIcon(null, g, x + at, y);
|
||||
}
|
||||
else {
|
||||
pattern.paintIcon(null, g, x, y + at);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,12 +333,12 @@ public class ImageLoader implements Serializable {
|
||||
if (w <= 0 || h <= 0) {
|
||||
return image;
|
||||
}
|
||||
int width = (int)Math.ceil(scale * w);
|
||||
int height = (int)Math.ceil(scale * h);
|
||||
int width = (int)Math.round(scale * w);
|
||||
int height = (int)Math.round(scale * h);
|
||||
// Using "QUALITY" instead of "ULTRA_QUALITY" results in images that are less blurry
|
||||
// because ultra quality performs a few more passes when scaling, which introduces blurriness
|
||||
// when the scaling factor is relatively small (i.e. <= 3.0f) -- which is the case here.
|
||||
return Scalr.resize(ImageUtil.toBufferedImage(image), Scalr.Method.QUALITY, width, height);
|
||||
return Scalr.resize(ImageUtil.toBufferedImage(image), Scalr.Method.QUALITY, Scalr.Mode.FIT_EXACT, width, height, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -25,7 +25,7 @@ import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ImageObserver;
|
||||
|
||||
import static java.lang.Math.ceil;
|
||||
import static java.lang.Math.round;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
@@ -152,7 +152,7 @@ public class JBHiDPIScaledImage extends BufferedImage {
|
||||
}
|
||||
JBHiDPIScaledImage newImg = new JBHiDPIScaledImage(newUserWidth, newUserHeight, getType());
|
||||
Graphics2D g = newImg.createGraphics();
|
||||
g.drawImage(scaled, 0, 0, (int)ceil(newUserWidth), (int)ceil(newUserHeight),
|
||||
g.drawImage(scaled, 0, 0, (int)round(newUserWidth), (int)round(newUserHeight),
|
||||
0, 0, scaled.getWidth(null), scaled.getHeight(null), null);
|
||||
g.dispose();
|
||||
return newImg;
|
||||
@@ -213,7 +213,7 @@ public class JBHiDPIScaledImage extends BufferedImage {
|
||||
* @return the width
|
||||
*/
|
||||
public int getUserWidth(ImageObserver observer) {
|
||||
return myImage != null ? (int)ceil(myUserWidth) : (int)ceil(super.getWidth(observer) / myScale);
|
||||
return myImage != null ? (int)round(myUserWidth) : (int)round(super.getWidth(observer) / myScale);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,7 +223,7 @@ public class JBHiDPIScaledImage extends BufferedImage {
|
||||
* @return the height
|
||||
*/
|
||||
public int getUserHeight(ImageObserver observer) {
|
||||
return myImage != null ? (int)ceil(myUserHeight) : (int)ceil(super.getHeight(observer) / myScale);
|
||||
return myImage != null ? (int)round(myUserHeight) : (int)round(super.getHeight(observer) / myScale);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,6 +61,7 @@ import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.im.InputContext;
|
||||
import java.awt.image.BufferedImage;
|
||||
@@ -2056,10 +2057,8 @@ public class UIUtil {
|
||||
dw = dstBounds.width;
|
||||
dh = dstBounds.height;
|
||||
}
|
||||
if (dw == -1 && dh == -1) {
|
||||
dw = ImageUtil.getUserWidth(image);
|
||||
dh = ImageUtil.getUserHeight(image);
|
||||
}
|
||||
boolean dstSizeUndefined = (dw == -1 && dh == -1);
|
||||
|
||||
int sx = 0;
|
||||
int sy = 0;
|
||||
int sw = -1;
|
||||
@@ -2070,11 +2069,21 @@ public class UIUtil {
|
||||
sw = srcBounds.width;
|
||||
sh = srcBounds.height;
|
||||
}
|
||||
if (sw == -1 && sh == -1) {
|
||||
sw = ImageUtil.getRealWidth(image);
|
||||
sh = ImageUtil.getRealHeight(image);
|
||||
boolean srcSizeUndefined = (sw == -1 && sh == -1);
|
||||
|
||||
if (dstSizeUndefined && srcSizeUndefined) {
|
||||
drawImage(g, image, null, dx, dy, -1, -1, observer);
|
||||
} else {
|
||||
if (dstSizeUndefined) {
|
||||
dw = ImageUtil.getUserWidth(image);
|
||||
dh = ImageUtil.getUserHeight(image);
|
||||
}
|
||||
if (srcSizeUndefined) {
|
||||
sw = ImageUtil.getRealWidth(image);
|
||||
sh = ImageUtil.getRealHeight(image);
|
||||
}
|
||||
g.drawImage(drawImage, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, observer);
|
||||
}
|
||||
g.drawImage(drawImage, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, observer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2085,44 +2094,59 @@ public class UIUtil {
|
||||
*/
|
||||
@Deprecated
|
||||
public static void drawImage(Graphics g, Image image, int x, int y, int width, int height, ImageObserver observer) {
|
||||
drawImage(g, image, null, x, y, width, height, observer);
|
||||
}
|
||||
|
||||
private static void drawImage(Graphics g, Image image, @Nullable BufferedImageOp op, int x, int y, int width, int height, ImageObserver observer) {
|
||||
double scale = 1d;
|
||||
Graphics2D invG = null;
|
||||
boolean srcSizeUndefined = (width == -1 && height == -1);
|
||||
int dstw = ImageUtil.getUserWidth(image);
|
||||
int dsth = ImageUtil.getUserHeight(image);
|
||||
|
||||
if (image instanceof JBHiDPIScaledImage) {
|
||||
Image img = ((JBHiDPIScaledImage)image).getDelegate();
|
||||
if (img == null) {
|
||||
img = image;
|
||||
JBHiDPIScaledImage hidpiImage = (JBHiDPIScaledImage)image;
|
||||
Image delegate = hidpiImage.getDelegate();
|
||||
if (delegate != null) image = delegate;
|
||||
scale = hidpiImage.getScale();
|
||||
|
||||
if (srcSizeUndefined) {
|
||||
AffineTransform tx = ((Graphics2D)g).getTransform();
|
||||
if (scale == tx.getScaleX()) {
|
||||
// The image has the same original scale as the graphics scale. However, the real image
|
||||
// scale - userSize/realSize - can suffer from inaccuracy due to the image user size
|
||||
// rounding to int (userSize = (int)realSize/originalImageScale). This may case quality
|
||||
// loss if the image is drawn via Graphics.drawImage(image, <srcRect>, <dstRect>)
|
||||
// due to scaling in Graphics. To avoid that, the image should be drawn directly via
|
||||
// Graphics.drawImage(image, 0, 0) on the unscaled Graphics.
|
||||
double gScaleX = tx.getScaleX();
|
||||
double gScaleY = tx.getScaleY();
|
||||
tx.scale(1 / gScaleX, 1 / gScaleY); // inverse the scale
|
||||
tx.translate(x * gScaleX, y * gScaleY); // scale x/y with double precision
|
||||
invG = (Graphics2D)g.create();
|
||||
invG.setTransform(tx);
|
||||
}
|
||||
}
|
||||
int dstw = width;
|
||||
int dsth = height;
|
||||
if (width == -1 && height == -1) {
|
||||
dstw = ImageUtil.getUserWidth(image);
|
||||
dsth = ImageUtil.getUserHeight(image);
|
||||
}
|
||||
int srcw = ImageUtil.getRealWidth(image);
|
||||
int srch = ImageUtil.getRealHeight(image);
|
||||
g.drawImage(img, x, y, x + dstw, y + dsth, 0, 0, srcw, srch, observer);
|
||||
}
|
||||
else if (width == -1 && height == -1) {
|
||||
g.drawImage(image, x, y, observer);
|
||||
if (op != null && image instanceof BufferedImage) {
|
||||
image = op.filter((BufferedImage)image, null);
|
||||
}
|
||||
if (invG != null) {
|
||||
invG.drawImage(image, 0, 0, observer);
|
||||
invG.dispose();
|
||||
}
|
||||
else if (srcSizeUndefined) {
|
||||
g.drawImage(image, x, y, dstw, dsth, observer);
|
||||
}
|
||||
else {
|
||||
g.drawImage(image, x, y, x + width, y + height, 0, 0, width, height, observer);
|
||||
int srcw = (int)Math.ceil(width * scale);
|
||||
int srch = (int)Math.ceil(height * scale);
|
||||
g.drawImage(image, x, y, x + width, y + height, 0, 0, srcw, srch, observer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawImage(Graphics g, BufferedImage image, BufferedImageOp op, int x, int y) {
|
||||
if (image instanceof JBHiDPIScaledImage) {
|
||||
Image img = ((JBHiDPIScaledImage)image).getDelegate();
|
||||
if (img == null) {
|
||||
img = image;
|
||||
}
|
||||
if (op != null && img instanceof BufferedImage) img = op.filter((BufferedImage)img, null);
|
||||
int dstw = ImageUtil.getUserWidth(image);
|
||||
int dsth = ImageUtil.getUserHeight(image);
|
||||
int srcw = ImageUtil.getRealWidth(image);
|
||||
int srch = ImageUtil.getRealHeight(image);
|
||||
g.drawImage(img, x, y, x + dstw, y + dsth, 0, 0, srcw, srch, null);
|
||||
} else {
|
||||
((Graphics2D)g).drawImage(image, op, x, y);
|
||||
}
|
||||
drawImage(g, image, op, x, y, -1, -1, null);
|
||||
}
|
||||
|
||||
public static void paintWithXorOnRetina(@NotNull Dimension size, @NotNull Graphics g, Consumer<Graphics2D> paintRoutine) {
|
||||
|
||||
Reference in New Issue
Block a user