1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.awt.Color;
  25 import java.awt.Frame;
  26 import java.awt.Graphics;
  27 import java.awt.GraphicsConfiguration;
  28 import java.awt.GraphicsDevice;
  29 import java.awt.Image;
  30 import java.awt.Rectangle;
  31 import java.awt.image.BufferedImage;
  32 import java.awt.image.BaseMultiResolutionImage;
  33 import static java.awt.RenderingHints.KEY_RESOLUTION_VARIANT;
  34 import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_SIZE_FIT;
  35 import java.awt.geom.AffineTransform;
  36 import java.awt.image.ColorModel;
  37 import java.awt.image.Raster;
  38 import sun.java2d.StateTrackable;
  39 import sun.java2d.SunGraphics2D;
  40 import sun.java2d.SurfaceData;
  41 import sun.java2d.loops.SurfaceType;
  42 
  43 /**
  44  * @test
  45  * @bug 8073320
  46  * @author Alexander Scherbatiy
  47  * @summary Windows HiDPI support
  48  * @modules java.desktop/sun.java2d java.desktop/sun.java2d.loops
  49  * @run main MultiResolutionDrawImageWithTransformTest
  50  */
  51 public class MultiResolutionDrawImageWithTransformTest {
  52 
  53     private static final int SCREEN_SIZE = 400;
  54     private static final int IMAGE_SIZE = SCREEN_SIZE / 4;
  55     private static final Color BACKGROUND_COLOR = Color.PINK;
  56     private static final Color[] COLORS = {
  57         Color.CYAN, Color.GREEN, Color.BLUE, Color.ORANGE
  58     };
  59 
  60     public static void main(String[] args) throws Exception {
  61 
  62         int length = COLORS.length;
  63         BufferedImage[] resolutionVariants = new BufferedImage[length];
  64         for (int i = 0; i < length; i++) {
  65             resolutionVariants[i] = createRVImage(getSize(i), COLORS[i]);
  66         }
  67 
  68         BaseMultiResolutionImage mrImage = new BaseMultiResolutionImage(
  69                 resolutionVariants);
  70 
  71         // scale 1, transform 1, resolution variant 1
  72         Color color = getImageColor(mrImage, 1, 1);
  73         if (!getColorForScale(1).equals(color)) {
  74             throw new RuntimeException("Wrong resolution variant!");
  75         }
  76 
  77         // scale 1, transform 2, resolution variant 2
  78         color = getImageColor(mrImage, 1, 2);
  79         if (!getColorForScale(2).equals(color)) {
  80             throw new RuntimeException("Wrong resolution variant!");
  81         }
  82 
  83         // scale 2, transform 1, resolution variant 2
  84         color = getImageColor(mrImage, 2, 1);
  85         if (!getColorForScale(2).equals(color)) {
  86             throw new RuntimeException("Wrong resolution variant!");
  87         }
  88 
  89         // scale 2, transform 2, resolution variant 4
  90         color = getImageColor(mrImage, 2, 2);
  91         if (!getColorForScale(4).equals(color)) {
  92             throw new RuntimeException("Wrong resolution variant!");
  93         }
  94     }
  95 
  96     private static Color getColorForScale(int scale) {
  97         return COLORS[scale - 1];
  98     }
  99 
 100     private static Color getImageColor(Image image, double configScale,
 101             double transformScale) {
 102 
 103         TestSurfaceData surface = new TestSurfaceData(SCREEN_SIZE, SCREEN_SIZE,
 104                 configScale);
 105         SunGraphics2D g2d = new SunGraphics2D(surface,
 106                 Color.BLACK, Color.BLACK, null);
 107         g2d.setRenderingHint(KEY_RESOLUTION_VARIANT,
 108                 VALUE_RESOLUTION_VARIANT_SIZE_FIT);
 109         AffineTransform tx = AffineTransform.getScaleInstance(transformScale,
 110                 transformScale);
 111         g2d.drawImage(image, tx, null);
 112         g2d.dispose();
 113 
 114         int backgroundX = (int) (1.5 * image.getWidth(null) * transformScale);
 115         int backgroundY = (int) (1.5 * image.getHeight(null) * transformScale);
 116         Color backgroundColor = surface.getColor(backgroundX, backgroundY);
 117         //surface.show(String.format("Config: %f, transform: %f", configScale, transformScale));
 118         if (!BACKGROUND_COLOR.equals(backgroundColor)) {
 119             throw new RuntimeException("Wrong background color!");
 120         }
 121         return surface.getColor(IMAGE_SIZE / 4, IMAGE_SIZE / 4);
 122     }
 123 
 124     private static int getSize(int i) {
 125         return (i + 1) * IMAGE_SIZE;
 126     }
 127 
 128     private static BufferedImage createRVImage(int size, Color color) {
 129         BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
 130         Graphics g = image.createGraphics();
 131         g.setColor(color);
 132         g.fillRect(0, 0, size, size);
 133         g.dispose();
 134         return image;
 135     }
 136 
 137     static class TestGraphicsConfig extends GraphicsConfiguration {
 138 
 139         private final double scale;
 140 
 141         TestGraphicsConfig(double scale) {
 142             this.scale = scale;
 143         }
 144 
 145         @Override
 146         public GraphicsDevice getDevice() {
 147             throw new UnsupportedOperationException("Not supported yet.");
 148         }
 149 
 150         @Override
 151         public ColorModel getColorModel() {
 152             throw new UnsupportedOperationException("Not supported yet.");
 153         }
 154 
 155         @Override
 156         public ColorModel getColorModel(int transparency) {
 157             throw new UnsupportedOperationException("Not supported yet.");
 158         }
 159 
 160         @Override
 161         public AffineTransform getDefaultTransform() {
 162             return AffineTransform.getScaleInstance(scale, scale);
 163         }
 164 
 165         @Override
 166         public AffineTransform getNormalizingTransform() {
 167             throw new UnsupportedOperationException("Not supported yet.");
 168         }
 169 
 170         @Override
 171         public Rectangle getBounds() {
 172             throw new UnsupportedOperationException("Not supported yet.");
 173         }
 174     }
 175 
 176     static class TestSurfaceData extends SurfaceData {
 177 
 178         private final int width;
 179         private final int height;
 180         private final GraphicsConfiguration gc;
 181         private final BufferedImage buffImage;
 182         private final double scale;
 183 
 184         public TestSurfaceData(int width, int height, double scale) {
 185             super(StateTrackable.State.DYNAMIC, SurfaceType.Custom, ColorModel.getRGBdefault());
 186             this.scale = scale;
 187             gc = new TestGraphicsConfig(scale);
 188             this.width = (int) Math.ceil(scale * width);
 189             this.height = (int) Math.ceil(scale * height);
 190             buffImage = new BufferedImage(this.width, this.height,
 191                     BufferedImage.TYPE_INT_RGB);
 192 
 193             Graphics imageGraphics = buffImage.createGraphics();
 194             imageGraphics.setColor(BACKGROUND_COLOR);
 195             imageGraphics.fillRect(0, 0, this.width, this.height);
 196             imageGraphics.dispose();
 197         }
 198 
 199         Color getColor(int x, int y) {
 200             int sx = (int) Math.ceil(x * scale);
 201             int sy = (int) Math.ceil(y * scale);
 202             return new Color(buffImage.getRGB(sx, sy));
 203         }
 204 
 205         @Override
 206         public SurfaceData getReplacement() {
 207             throw new UnsupportedOperationException("Not supported yet.");
 208         }
 209 
 210         @Override
 211         public GraphicsConfiguration getDeviceConfiguration() {
 212             return gc;
 213         }
 214 
 215         @Override
 216         public Raster getRaster(int x, int y, int w, int h) {
 217             return buffImage.getRaster();
 218         }
 219 
 220         @Override
 221         public Rectangle getBounds() {
 222             return new Rectangle(0, 0, width, height);
 223         }
 224 
 225         @Override
 226         public Object getDestination() {
 227             throw new UnsupportedOperationException("Not supported yet.");
 228         }
 229 
 230         private void show(String title) {
 231             Frame frame = new Frame() {
 232 
 233                 @Override
 234                 public void paint(Graphics g) {
 235                     super.paint(g);
 236                     g.drawImage(buffImage, 0, 0, this);
 237                     g.setColor(Color.GRAY);
 238                     g.drawRect(0, 0, width, height);
 239                     g.drawRect(0, height / 2, width, height / 2);
 240                     g.drawRect(width / 2, 0, width / 2, height);
 241                 }
 242             };
 243             frame.setTitle(title);
 244             frame.setSize(width, height);
 245             frame.setVisible(true);
 246         }
 247     }
 248 }