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 import java.awt.Color;
  24 import java.awt.Graphics;
  25 import java.awt.GraphicsConfiguration;
  26 import java.awt.GraphicsDevice;
  27 import java.awt.Image;
  28 import java.awt.Rectangle;
  29 import java.awt.image.BufferedImage;
  30 import java.awt.image.BaseMultiResolutionImage;
  31 import static java.awt.RenderingHints.KEY_RESOLUTION_VARIANT;
  32 import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_BASE;
  33 import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_DPI_FIT;
  34 import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_SIZE_FIT;
  35 import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_DEFAULT;
  36 import java.awt.geom.AffineTransform;
  37 import java.awt.image.ColorModel;
  38 import java.awt.image.Raster;
  39 import sun.java2d.StateTrackable;
  40 import sun.java2d.SunGraphics2D;
  41 import sun.java2d.SurfaceData;
  42 import sun.java2d.loops.SurfaceType;
  43 
  44 /**
  45  * @test
  46  * @bug 8029339
  47  * @author Alexander Scherbatiy
  48  * @summary Custom MultiResolution image support on HiDPI displays
  49  * @modules java.desktop/sun.java2d
  50  * @modules java.desktop/sun.java2d.loops
  51  * @run main MultiResolutionRenderingHintsTest
  52  */
  53 public class MultiResolutionRenderingHintsTest {
  54 
  55     private static final int BASE_SIZE = 200;
  56     private static final Color[] COLORS = {
  57         Color.CYAN, Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED, Color.PINK
  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         // base
  72         Color color = getImageColor(VALUE_RESOLUTION_VARIANT_BASE, mrImage, 2, 3);
  73         if (!getColorForScale(1).equals(color)) {
  74             throw new RuntimeException("Wrong base resolution variant!");
  75         }
  76 
  77         // dpi fit
  78         color = getImageColor(VALUE_RESOLUTION_VARIANT_DPI_FIT, mrImage, 2, 3);
  79         if (!getColorForScale(2).equals(color)) {
  80             throw new RuntimeException("Resolution variant is not based on dpi!");
  81         }
  82 
  83         // size fit
  84         color = getImageColor(VALUE_RESOLUTION_VARIANT_SIZE_FIT, mrImage, 2, 3);
  85         if (!getColorForScale(6).equals(color)) {
  86             throw new RuntimeException("Resolution variant is not based on"
  87                     + " rendered size!");
  88         }
  89 
  90         // default
  91         // depends on the policies of the platform
  92         // just check that exception is not thrown
  93         getImageColor(VALUE_RESOLUTION_VARIANT_DEFAULT, mrImage, 2, 3);
  94     }
  95 
  96     private static Color getColorForScale(int scale) {
  97         return COLORS[scale - 1];
  98     }
  99 
 100     private static Color getImageColor(final Object renderingHint, Image image,
 101             double configScale, double graphicsScale) {
 102 
 103         int width = image.getWidth(null);
 104         int height = image.getHeight(null);
 105 
 106         TestSurfaceData surface = new TestSurfaceData(width, height, configScale);
 107         SunGraphics2D g2d = new SunGraphics2D(surface,
 108                 Color.BLACK, Color.BLACK, null);
 109         g2d.setRenderingHint(KEY_RESOLUTION_VARIANT, renderingHint);
 110         g2d.scale(graphicsScale, graphicsScale);
 111         g2d.drawImage(image, 0, 0, null);
 112         g2d.dispose();
 113         return surface.getColor(width / 2, height / 2);
 114     }
 115 
 116     private static int getSize(int i) {
 117         return (i + 1) * BASE_SIZE;
 118     }
 119 
 120     private static BufferedImage createRVImage(int size, Color color) {
 121         BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
 122         Graphics g = image.createGraphics();
 123         g.setColor(Color.BLACK);
 124         g.fillRect(0, 0, size, size);
 125         g.setColor(color);
 126         g.fillOval(0, 0, size, size);
 127         g.dispose();
 128         return image;
 129     }
 130 
 131     static class TestGraphicsConfig extends GraphicsConfiguration {
 132 
 133         private final double scale;
 134 
 135         TestGraphicsConfig(double scale) {
 136             this.scale = scale;
 137         }
 138 
 139         @Override
 140         public GraphicsDevice getDevice() {
 141             throw new UnsupportedOperationException("Not supported yet.");
 142         }
 143 
 144         @Override
 145         public ColorModel getColorModel() {
 146             throw new UnsupportedOperationException("Not supported yet.");
 147         }
 148 
 149         @Override
 150         public ColorModel getColorModel(int transparency) {
 151             throw new UnsupportedOperationException("Not supported yet.");
 152         }
 153 
 154         @Override
 155         public AffineTransform getDefaultTransform() {
 156             return AffineTransform.getScaleInstance(scale, scale);
 157         }
 158 
 159         @Override
 160         public AffineTransform getNormalizingTransform() {
 161             throw new UnsupportedOperationException("Not supported yet.");
 162         }
 163 
 164         @Override
 165         public Rectangle getBounds() {
 166             throw new UnsupportedOperationException("Not supported yet.");
 167         }
 168     }
 169 
 170     static class TestSurfaceData extends SurfaceData {
 171 
 172         private final int width;
 173         private final int height;
 174         private final GraphicsConfiguration gc;
 175         private final BufferedImage buffImage;
 176         private final double scale;
 177 
 178         public TestSurfaceData(int width, int height, double scale) {
 179             super(StateTrackable.State.DYNAMIC, SurfaceType.Custom, ColorModel.getRGBdefault());
 180             this.scale = scale;
 181             gc = new TestGraphicsConfig(scale);
 182             this.width = (int) Math.ceil(scale * width);
 183             this.height = (int) Math.ceil(scale * height);
 184             buffImage = new BufferedImage(this.width, this.height,
 185                     BufferedImage.TYPE_INT_RGB);
 186         }
 187 
 188         Color getColor(int x, int y) {
 189             int sx = (int) Math.ceil(x * scale);
 190             int sy = (int) Math.ceil(y * scale);
 191             return new Color(buffImage.getRGB(sx, sy));
 192         }
 193 
 194         @Override
 195         public SurfaceData getReplacement() {
 196             throw new UnsupportedOperationException("Not supported yet.");
 197         }
 198 
 199         @Override
 200         public GraphicsConfiguration getDeviceConfiguration() {
 201             return gc;
 202         }
 203 
 204         @Override
 205         public Raster getRaster(int x, int y, int w, int h) {
 206             return buffImage.getRaster();
 207         }
 208 
 209         @Override
 210         public Rectangle getBounds() {
 211             return new Rectangle(0, 0, width, height);
 212         }
 213 
 214         @Override
 215         public Object getDestination() {
 216             throw new UnsupportedOperationException("Not supported yet.");
 217         }
 218     }
 219 }