jdk/test/java/awt/image/multiresolution/MultiResolutionRenderingHintsTest.java
author alexsch
Tue, 15 Sep 2015 15:31:34 +0400
changeset 32682 6f1200d8999d
child 36867 d3169e0913e7
permissions -rw-r--r--
8029339: Custom MultiResolution image support on HiDPI displays Reviewed-by: flar, serb

/*
 * Copyright (c) 2015, 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.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.BaseMultiResolutionImage;
import static java.awt.RenderingHints.KEY_RESOLUTION_VARIANT;
import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_BASE;
import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_DPI_FIT;
import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_SIZE_FIT;
import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_DEFAULT;
import java.awt.geom.AffineTransform;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import sun.java2d.StateTrackable;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.SurfaceType;

/**
 * @test
 * @bug 8029339
 * @author Alexander Scherbatiy
 * @summary Custom MultiResolution image support on HiDPI displays
 * @modules java.desktop/sun.java2d
 * @run main MultiResolutionRenderingHintsTest
 */
public class MultiResolutionRenderingHintsTest {

    private static final int BASE_SIZE = 200;
    private static final Color[] COLORS = {
        Color.CYAN, Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED, Color.PINK
    };

    public static void main(String[] args) throws Exception {

        int length = COLORS.length;
        BufferedImage[] resolutionVariants = new BufferedImage[length];
        for (int i = 0; i < length; i++) {
            resolutionVariants[i] = createRVImage(getSize(i), COLORS[i]);
        }

        BaseMultiResolutionImage mrImage = new BaseMultiResolutionImage(
                resolutionVariants);

        // base
        Color color = getImageColor(VALUE_RESOLUTION_VARIANT_BASE, mrImage, 2, 3);
        if (!getColorForScale(1).equals(color)) {
            throw new RuntimeException("Wrong base resolution variant!");
        }

        // dpi fit
        color = getImageColor(VALUE_RESOLUTION_VARIANT_DPI_FIT, mrImage, 2, 3);
        if (!getColorForScale(2).equals(color)) {
            throw new RuntimeException("Resolution variant is not based on dpi!");
        }

        // size fit
        color = getImageColor(VALUE_RESOLUTION_VARIANT_SIZE_FIT, mrImage, 2, 3);
        if (!getColorForScale(6).equals(color)) {
            throw new RuntimeException("Resolution variant is not based on"
                    + " rendered size!");
        }

        // default
        // depends on the policies of the platform
        // just check that exception is not thrown
        getImageColor(VALUE_RESOLUTION_VARIANT_DEFAULT, mrImage, 2, 3);
    }

    private static Color getColorForScale(int scale) {
        return COLORS[scale - 1];
    }

    private static Color getImageColor(final Object renderingHint, Image image,
            double configScale, double graphicsScale) {

        int width = image.getWidth(null);
        int height = image.getHeight(null);

        TestSurfaceData surface = new TestSurfaceData(width, height, configScale);
        SunGraphics2D g2d = new SunGraphics2D(surface,
                Color.BLACK, Color.BLACK, null);
        g2d.setRenderingHint(KEY_RESOLUTION_VARIANT, renderingHint);
        g2d.scale(graphicsScale, graphicsScale);
        g2d.drawImage(image, 0, 0, null);
        g2d.dispose();
        return surface.getColor(width / 2, height / 2);
    }

    private static int getSize(int i) {
        return (i + 1) * BASE_SIZE;
    }

    private static BufferedImage createRVImage(int size, Color color) {
        BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.createGraphics();
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, size, size);
        g.setColor(color);
        g.fillOval(0, 0, size, size);
        g.dispose();
        return image;
    }

    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;
        private final double scale;

        public TestSurfaceData(int width, int height, double scale) {
            super(StateTrackable.State.DYNAMIC, SurfaceType.Custom, ColorModel.getRGBdefault());
            this.scale = scale;
            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);
        }

        Color getColor(int x, int y) {
            int sx = (int) Math.ceil(x * scale);
            int sy = (int) Math.ceil(y * scale);
            return new Color(buffImage.getRGB(sx, sy));
        }

        @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.");
        }
    }
}