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.*;
25import java.awt.image.BufferedImage;
26import java.awt.image.VolatileImage;
27import static sun.awt.OSInfo.*;
28
29/**
30 * @test
31 * @key headful
32 * @bug 8069348
33 * @summary SunGraphics2D.copyArea() does not properly work for scaled graphics
34 * @modules java.desktop/sun.awt
35 * @run main/othervm -Dsun.java2d.uiScale=2 CopyScaledAreaTest
36 * @run main/othervm -Dsun.java2d.opengl=true -Dsun.java2d.uiScale=2 CopyScaledAreaTest
37 * @run main/othervm -Dsun.java2d.d3d=true    -Dsun.java2d.uiScale=2 CopyScaledAreaTest
38 * @run main/othervm -Dsun.java2d.d3d=false   -Dsun.java2d.opengl=false
39 *                   -Dsun.java2d.uiScale=2 CopyScaledAreaTest
40 */
41public class CopyScaledAreaTest {
42
43    private static final int IMAGE_WIDTH = 800;
44    private static final int IMAGE_HEIGHT = 800;
45    private static final int X = 50;
46    private static final int Y = 50;
47    private static final int W = 100;
48    private static final int H = 75;
49    private static final int DX = 15;
50    private static final int DY = 10;
51    private static final int N = 3;
52    private static final Color BACKGROUND_COLOR = Color.YELLOW;
53    private static final Color FILL_COLOR = Color.ORANGE;
54    private static final double[][] SCALES = {{1.3, 1.4}, {0.3, 2.3}, {2.7, 0.1}};
55
56    private static boolean isSupported() {
57        String d3d = System.getProperty("sun.java2d.d3d");
58        return !Boolean.getBoolean(d3d) || getOSType() == OSType.WINDOWS;
59    }
60
61    private static int scale(int x, double scale) {
62        return (int) Math.floor(x * scale);
63    }
64
65    private static VolatileImage createVolatileImage(GraphicsConfiguration conf) {
66        return conf.createCompatibleVolatileImage(IMAGE_WIDTH, IMAGE_HEIGHT);
67    }
68
69    // rendering to the image
70    private static void renderOffscreen(VolatileImage vImg,
71                                        GraphicsConfiguration conf,
72                                        double scaleX,
73                                        double scaleY)
74    {
75        int attempts = 0;
76        do {
77
78            if (attempts > 10) {
79                throw new RuntimeException("Too many attempts!");
80            }
81
82            if (vImg.validate(conf) == VolatileImage.IMAGE_INCOMPATIBLE) {
83                // old vImg doesn't work with new GraphicsConfig; re-create it
84                vImg = createVolatileImage(conf);
85            }
86            Graphics2D g = vImg.createGraphics();
87            //
88            // miscellaneous rendering commands...
89            //
90            g.setColor(BACKGROUND_COLOR);
91            g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
92            g.scale(scaleX, scaleY);
93
94            g.setColor(FILL_COLOR);
95            g.fillRect(X, Y, W, H);
96
97            for (int i = 0; i < N; i++) {
98                g.copyArea(X + i * DX, Y + i * DY, W, H, DX, DY);
99            }
100            g.dispose();
101            attempts++;
102        } while (vImg.contentsLost());
103    }
104
105    public static void main(String[] args) throws Exception {
106
107        if (!isSupported()) {
108            return;
109        }
110
111        GraphicsConfiguration graphicsConfiguration =
112                GraphicsEnvironment.getLocalGraphicsEnvironment()
113                .getDefaultScreenDevice().getDefaultConfiguration();
114
115        for(double[] scales: SCALES){
116            testScale(scales[0], scales[1], graphicsConfiguration);
117        }
118    }
119
120    private static void testScale(double scaleX, double scaleY,
121                                  GraphicsConfiguration gc) throws Exception
122    {
123
124        BufferedImage buffImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT,
125                                                    BufferedImage.TYPE_INT_RGB);
126        Graphics g = buffImage.createGraphics();
127
128        VolatileImage vImg = createVolatileImage(gc);
129
130        int attempts = 0;
131        do {
132
133            if (attempts > 10) {
134                throw new RuntimeException("Too many attempts!");
135            }
136
137            int returnCode = vImg.validate(gc);
138            if (returnCode == VolatileImage.IMAGE_RESTORED) {
139                // Contents need to be restored
140                renderOffscreen(vImg, gc, scaleX, scaleY); // restore contents
141            } else if (returnCode == VolatileImage.IMAGE_INCOMPATIBLE) {
142                // old vImg doesn't work with new GraphicsConfig; re-create it
143                vImg = createVolatileImage(gc);
144                renderOffscreen(vImg, gc, scaleX, scaleY);
145            }
146            g.drawImage(vImg, 0, 0, null);
147            attempts++;
148        } while (vImg.contentsLost());
149
150        g.dispose();
151
152        int x = scale(X + N * DX, scaleX) + 1;
153        int y = scale(Y + N * DY, scaleY) + 1;
154        int w = scale(W, scaleX) - 2;
155        int h = scale(H, scaleY) - 2;
156
157        for (int i = x; i < x + w; i++) {
158            for (int j = y; j < y + h; j++) {
159                if (buffImage.getRGB(i, j) != FILL_COLOR.getRGB()) {
160                    throw new RuntimeException("Wrong rectangle color!");
161                }
162            }
163        }
164    }
165}
166