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