/* * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.awt.Color; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.awt.geom.AffineTransform; import java.awt.image.ColorModel; import java.awt.image.Raster; import java.util.Arrays; import sun.java2d.StateTrackable; import sun.java2d.SunGraphics2D; import sun.java2d.SurfaceData; import sun.java2d.loops.SurfaceType; /** * @test * @bug 8142966 * @author Alexander Scherbatiy * @summary Wrong cursor position in text components on HiDPI display * @modules java.desktop/sun.java2d java.desktop/sun.java2d.loops */ public class HiDPIGlyphAdvanceTest { private static final int SCREEN_SIZE = 400; private static final Color BACKGROUND_COLOR = Color.WHITE; public static void main(String[] args) throws Exception { char[] chars = ("abcdefghijklmnopqrstuwxyz" + "ABCDEFGHIJKLMNOPQRSTUWXYZ").toCharArray(); int textWidth1 = getTextWidth(chars, 1); int textWidth2 = getTextWidth(chars, 2); if (textWidth1 != textWidth2) { throw new RuntimeException("Glyph advances are not the same" + " for different UI scale factors!"); } } private static int getTextWidth(char[] chars, double configScale) { TestSurfaceData surface = new TestSurfaceData(SCREEN_SIZE, SCREEN_SIZE, configScale); SunGraphics2D g2d = new SunGraphics2D(surface, Color.BLACK, Color.BLACK, null); FontMetrics fm = g2d.getFontMetrics(); int textWidth = fm.charsWidth(chars, 0, chars.length); g2d.dispose(); return textWidth; } static class TestGraphicsConfig extends GraphicsConfiguration { private final double scale; TestGraphicsConfig(double scale) { this.scale = scale; } @Override public GraphicsDevice getDevice() { throw new UnsupportedOperationException("Not supported yet."); } @Override public ColorModel getColorModel() { throw new UnsupportedOperationException("Not supported yet."); } @Override public ColorModel getColorModel(int transparency) { throw new UnsupportedOperationException("Not supported yet."); } @Override public AffineTransform getDefaultTransform() { return AffineTransform.getScaleInstance(scale, scale); } @Override public AffineTransform getNormalizingTransform() { throw new UnsupportedOperationException("Not supported yet."); } @Override public Rectangle getBounds() { throw new UnsupportedOperationException("Not supported yet."); } } static class TestSurfaceData extends SurfaceData { private final int width; private final int height; private final GraphicsConfiguration gc; private final BufferedImage buffImage; public TestSurfaceData(int width, int height, double scale) { super(StateTrackable.State.DYNAMIC, SurfaceType.Custom, ColorModel.getRGBdefault()); gc = new TestGraphicsConfig(scale); this.width = (int) Math.ceil(scale * width); this.height = (int) Math.ceil(scale * height); buffImage = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_RGB); Graphics imageGraphics = buffImage.createGraphics(); imageGraphics.setColor(BACKGROUND_COLOR); imageGraphics.fillRect(0, 0, this.width, this.height); imageGraphics.dispose(); } @Override public SurfaceData getReplacement() { throw new UnsupportedOperationException("Not supported yet."); } @Override public GraphicsConfiguration getDeviceConfiguration() { return gc; } @Override public Raster getRaster(int x, int y, int w, int h) { return buffImage.getRaster(); } @Override public Rectangle getBounds() { return new Rectangle(0, 0, width, height); } @Override public Object getDestination() { throw new UnsupportedOperationException("Not supported yet."); } } }