1 /*
   2  * Copyright (c) 2014, 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 
  24 import java.awt.Color;
  25 import java.awt.Graphics2D;
  26 import java.awt.GraphicsConfiguration;
  27 import java.awt.GraphicsEnvironment;
  28 import java.awt.Image;
  29 import java.awt.Rectangle;
  30 import java.awt.Shape;
  31 import java.awt.geom.AffineTransform;
  32 import java.awt.image.BufferedImage;
  33 import java.awt.image.DataBuffer;
  34 import java.awt.image.DataBufferByte;
  35 import java.awt.image.DataBufferInt;
  36 import java.awt.image.DataBufferShort;
  37 import java.awt.image.VolatileImage;
  38 import java.io.File;
  39 import java.io.IOException;
  40 
  41 import javax.imageio.ImageIO;
  42 
  43 import static java.awt.geom.Rectangle2D.Double;
  44 
  45 /**
  46  * @test
  47  * @bug 8061456
  48  * @summary Tests drawing BI to volatile image using different clips + xor mode.
  49  *          Results of the blit BI to compatibleImage is used for comparison.
  50  * @author Sergey Bylokhov
  51  */
  52 public final class IncorrectClipXorModeSW2Surface {
  53 
  54     private static int[] SIZES = {2, 10, 100};
  55     private static final Shape[] SHAPES = {
  56                                            new Rectangle(0, 0, 0, 0),
  57                                            new Rectangle(0, 0, 1, 1),
  58                                            new Rectangle(0, 1, 1, 1),
  59                                            new Rectangle(1, 0, 1, 1),
  60                                            new Rectangle(1, 1, 1, 1),
  61 
  62                                            new Double(0, 0, 0.5, 0.5),
  63                                            new Double(0, 0.5, 0.5, 0.5),
  64                                            new Double(0.5, 0, 0.5, 0.5),
  65                                            new Double(0.5, 0.5, 0.5, 0.5),
  66                                            new Double(0.25, 0.25, 0.5, 0.5),
  67                                            new Double(0, 0.25, 1, 0.5),
  68                                            new Double(0.25, 0, 0.5, 1),
  69 
  70                                            new Double(.10, .10, .20, .20),
  71                                            new Double(.75, .75, .20, .20),
  72                                            new Double(.75, .10, .20, .20),
  73                                            new Double(.10, .75, .20, .20),
  74     };
  75 
  76     public static void main(final String[] args) throws IOException {
  77         GraphicsEnvironment ge = GraphicsEnvironment
  78                 .getLocalGraphicsEnvironment();
  79         GraphicsConfiguration gc = ge.getDefaultScreenDevice()
  80                                      .getDefaultConfiguration();
  81         AffineTransform at;
  82         for (int size : SIZES) {
  83             at = AffineTransform.getScaleInstance(size, size);
  84             for (Shape clip : SHAPES) {
  85                 clip = at.createTransformedShape(clip);
  86                 for (Shape to : SHAPES) {
  87                     to = at.createTransformedShape(to);
  88                     // Prepare test images
  89                     BufferedImage snapshot;
  90                     BufferedImage bi = getBufferedImage(size);
  91                     VolatileImage vi = getVolatileImage(gc, size);
  92                     while (true) {
  93                         vi.validate(gc);
  94                         Graphics2D g2d = vi.createGraphics();
  95                         g2d.setColor(Color.GREEN);
  96                         g2d.fillRect(0, 0, size, size);
  97                         g2d.dispose();
  98                         if (vi.validate(gc) != VolatileImage.IMAGE_OK) {
  99                             continue;
 100                         }
 101                         draw(clip, to, bi, vi);
 102                         snapshot = vi.getSnapshot();
 103                         if (vi.contentsLost()) {
 104                             continue;
 105                         }
 106                         break;
 107                     }
 108                     // Prepare gold images
 109                     BufferedImage goldvi = getCompatibleImage(gc, size);
 110                     BufferedImage goldbi = getBufferedImage(size);
 111                     draw(clip, to, goldbi, goldvi);
 112                     validate(snapshot, goldvi);
 113                     vi.flush();
 114                 }
 115             }
 116         }
 117     }
 118 
 119     private static void draw(Shape clip, Shape shape, Image from, Image to) {
 120         Graphics2D g2d = (Graphics2D) to.getGraphics();
 121         g2d.setXORMode(Color.BLACK);
 122         g2d.setClip(clip);
 123         Rectangle toBounds = shape.getBounds();
 124         g2d.drawImage(from, toBounds.x, toBounds.y, toBounds.width,
 125                       toBounds.height, null);
 126         g2d.dispose();
 127     }
 128 
 129     private static BufferedImage getBufferedImage(int sw) {
 130         final BufferedImage bi = new BufferedImage(sw, sw, BufferedImage.TYPE_INT_ARGB);
 131         Graphics2D g2d = bi.createGraphics();
 132         g2d.setColor(Color.RED);
 133         g2d.fillRect(0, 0, sw, sw);
 134         g2d.dispose();
 135 
 136         final DataBuffer db = bi.getRaster().getDataBuffer();
 137         if (db instanceof DataBufferInt) {
 138             ((DataBufferInt) db).getData();
 139         } else if (db instanceof DataBufferShort) {
 140             ((DataBufferShort) db).getData();
 141         } else if (db instanceof DataBufferByte) {
 142             ((DataBufferByte) db).getData();
 143         } else {
 144             try {
 145                 bi.setAccelerationPriority(0.0f);
 146             } catch (final Throwable ignored) {
 147             }
 148         }
 149         return bi;
 150     }
 151 
 152     private static VolatileImage getVolatileImage(GraphicsConfiguration gc,
 153                                                   int size) {
 154         return gc.createCompatibleVolatileImage(size, size);
 155     }
 156 
 157     private static BufferedImage getCompatibleImage(GraphicsConfiguration gc,
 158                                                     int size) {
 159         BufferedImage image = gc.createCompatibleImage(size, size);
 160         Graphics2D g2d = image.createGraphics();
 161         g2d.setColor(Color.GREEN);
 162         g2d.fillRect(0, 0, size, size);
 163         g2d.dispose();
 164         return image;
 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 }