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