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 */
23import java.awt.Color;
24import java.awt.Graphics;
25import java.awt.GraphicsConfiguration;
26import java.awt.GraphicsDevice;
27import java.awt.Image;
28import java.awt.Rectangle;
29import java.awt.image.BufferedImage;
30import java.awt.image.BaseMultiResolutionImage;
31import static java.awt.RenderingHints.KEY_RESOLUTION_VARIANT;
32import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_BASE;
33import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_DPI_FIT;
34import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_SIZE_FIT;
35import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_DEFAULT;
36import java.awt.geom.AffineTransform;
37import java.awt.image.ColorModel;
38import java.awt.image.Raster;
39import sun.java2d.StateTrackable;
40import sun.java2d.SunGraphics2D;
41import sun.java2d.SurfaceData;
42import 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 */
53public 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}
220