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.Graphics2D;
26import java.awt.GraphicsConfiguration;
27import java.awt.GraphicsEnvironment;
28import java.awt.Image;
29import java.awt.Rectangle;
30import java.awt.Shape;
31import java.awt.geom.AffineTransform;
32import java.awt.image.BufferedImage;
33import java.awt.image.VolatileImage;
34import java.io.File;
35import java.io.IOException;
36
37import javax.imageio.ImageIO;
38
39import static java.awt.geom.Rectangle2D.Double;
40
41/**
42 * @test
43 * @key headful
44 * @bug 8061831 8130400
45 * @summary Tests drawing volatile image to volatile image using different
46 *          clips + xor mode. Results of the blit compatibleImage to
47 *          compatibleImage is used for comparison.
48 */
49public final class IncorrectClipXorModeSurface2Surface {
50
51    private static int[] SIZES = {2, 10, 100};
52    private static final Shape[] SHAPES = {
53            new Rectangle(0, 0, 0, 0),
54            new Rectangle(0, 0, 1, 1),
55            new Rectangle(0, 1, 1, 1),
56            new Rectangle(1, 0, 1, 1),
57            new Rectangle(1, 1, 1, 1),
58
59            new Double(0, 0, 0.5, 0.5),
60            new Double(0, 0.5, 0.5, 0.5),
61            new Double(0.5, 0, 0.5, 0.5),
62            new Double(0.5, 0.5, 0.5, 0.5),
63            new Double(0.25, 0.25, 0.5, 0.5),
64            new Double(0, 0.25, 1, 0.5),
65            new Double(0.25, 0, 0.5, 1),
66
67            new Double(.10, .10, .20, .20),
68            new Double(.75, .75, .20, .20),
69            new Double(.75, .10, .20, .20),
70            new Double(.10, .75, .20, .20),
71    };
72
73    public static void main(final String[] args) throws IOException {
74        GraphicsEnvironment ge = GraphicsEnvironment
75                .getLocalGraphicsEnvironment();
76        GraphicsConfiguration gc = ge.getDefaultScreenDevice()
77                .getDefaultConfiguration();
78        AffineTransform at;
79        for (int size : SIZES) {
80            at = AffineTransform.getScaleInstance(size, size);
81            for (Shape clip : SHAPES) {
82                clip = at.createTransformedShape(clip);
83                for (Shape to : SHAPES) {
84                    to = at.createTransformedShape(to);
85                    // Prepare test images
86                    BufferedImage snapshot;
87                    VolatileImage source = getVolatileImage(gc, size);
88                    VolatileImage target = getVolatileImage(gc, size);
89                    int attempt = 0;
90                    while (true) {
91                        if (++attempt > 10) {
92                            throw new RuntimeException("Too many attempts: " + attempt);
93                        }
94                        // Prepare source images
95                        source.validate(gc);
96                        Graphics2D g2d = source.createGraphics();
97                        g2d.setColor(Color.RED);
98                        g2d.fillRect(0, 0, size, size);
99                        g2d.dispose();
100                        if (source.validate(gc) != VolatileImage.IMAGE_OK) {
101                            continue;
102                        }
103                        // Prepare target images
104                        target.validate(gc);
105                        g2d = target.createGraphics();
106                        g2d.setColor(Color.GREEN);
107                        g2d.fillRect(0, 0, size, size);
108                        g2d.dispose();
109                        if (target.validate(gc) != VolatileImage.IMAGE_OK) {
110                            continue;
111                        }
112
113                        draw(clip, to, source, target);
114                        snapshot = target.getSnapshot();
115                        if (source.contentsLost() || target.contentsLost()) {
116                            continue;
117                        }
118                        break;
119                    }
120                    // Prepare gold images
121                    BufferedImage goldS = getSourceGold(gc, size);
122                    BufferedImage goldT = getTargetGold(gc, size);
123                    draw(clip, to, goldS, goldT);
124                    validate(snapshot, goldT);
125                    source.flush();
126                    target.flush();
127                }
128            }
129        }
130    }
131
132    private static void draw(Shape clip, Shape shape, Image from, Image to) {
133        Graphics2D g2d = (Graphics2D) to.getGraphics();
134        g2d.setXORMode(Color.BLACK);
135        g2d.setClip(clip);
136        Rectangle toBounds = shape.getBounds();
137        g2d.drawImage(from, toBounds.x, toBounds.y, toBounds.width,
138                      toBounds.height, null);
139        g2d.dispose();
140    }
141
142    private static BufferedImage getSourceGold(GraphicsConfiguration gc,
143                                               int size) {
144        final BufferedImage bi = gc.createCompatibleImage(size, size);
145        Graphics2D g2d = bi.createGraphics();
146        g2d.setColor(Color.RED);
147        g2d.fillRect(0, 0, size, size);
148        g2d.dispose();
149        return bi;
150    }
151
152    private static BufferedImage getTargetGold(GraphicsConfiguration gc,
153                                               int size) {
154        BufferedImage image = gc.createCompatibleImage(size, size);
155        Graphics2D g2d = image.createGraphics();
156        g2d.setColor(Color.GREEN);
157        g2d.fillRect(0, 0, size, size);
158        g2d.dispose();
159        return image;
160    }
161
162    private static VolatileImage getVolatileImage(GraphicsConfiguration gc,
163                                                  int size) {
164        return gc.createCompatibleVolatileImage(size, size);
165    }
166
167    private static void validate(BufferedImage bi, BufferedImage goldbi)
168            throws IOException {
169        for (int x = 0; x < bi.getWidth(); ++x) {
170            for (int y = 0; y < bi.getHeight(); ++y) {
171                if (goldbi.getRGB(x, y) != bi.getRGB(x, y)) {
172                    ImageIO.write(bi, "png", new File("actual.png"));
173                    ImageIO.write(goldbi, "png", new File("expected.png"));
174                    throw new RuntimeException("Test failed.");
175                }
176            }
177        }
178    }
179}
180