1 /*
   2  * Copyright (c) 2007, 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  * @test
  25  * @key headful
  26  * @bug 5009033 6603000 6666362
  27  * @summary Verifies that images transformed with bilinear filtering do not
  28  * leave artifacts at the edges.
  29  * @run main/othervm DrawImageBilinear
  30  * @run main/othervm -Dsun.java2d.opengl=True DrawImageBilinear
  31  * @author campbelc
  32  */
  33 
  34 import java.awt.Canvas;
  35 import java.awt.Color;
  36 import java.awt.Component;
  37 import java.awt.Dimension;
  38 import java.awt.Frame;
  39 import java.awt.Graphics;
  40 import java.awt.Graphics2D;
  41 import java.awt.GraphicsConfiguration;
  42 import java.awt.Point;
  43 import java.awt.Rectangle;
  44 import java.awt.RenderingHints;
  45 import java.awt.Robot;
  46 import java.awt.Toolkit;
  47 import java.awt.image.BufferedImage;
  48 import java.awt.image.IndexColorModel;
  49 import java.awt.image.VolatileImage;
  50 
  51 public class DrawImageBilinear extends Canvas {
  52 
  53     private static final int SIZE = 5;
  54 
  55     private static boolean done;
  56     private BufferedImage bimg1, bimg2;
  57     private VolatileImage vimg;
  58     private static volatile BufferedImage capture;
  59     private static void doCapture(Component test) {
  60         try {
  61             Thread.sleep(2000);
  62         } catch (InterruptedException ex) {}
  63         // Grab the screen region
  64         try {
  65             Robot robot = new Robot();
  66             Point pt1 = test.getLocationOnScreen();
  67             Rectangle rect =
  68                 new Rectangle(pt1.x, pt1.y, test.getWidth(), test.getHeight());
  69             capture = robot.createScreenCapture(rect);
  70         } catch (Exception e) {
  71             e.printStackTrace();
  72         }
  73     }
  74 
  75     private void renderPattern(Graphics g) {
  76         g.setColor(Color.red);
  77         g.fillRect(0, 0, SIZE, SIZE);
  78         //g.setColor(Color.green);
  79         //g.drawRect(0, 0, SIZE-1, SIZE-1);
  80         g.dispose();
  81     }
  82 
  83     public void paint(Graphics g) {
  84         Graphics2D g2d = (Graphics2D)g;
  85 
  86         if (bimg1 == null) {
  87             bimg1 = (BufferedImage)createImage(SIZE, SIZE);
  88             bimg1.setAccelerationPriority(0.0f);
  89             renderPattern(bimg1.createGraphics());
  90 
  91             bimg2 = (BufferedImage)createImage(SIZE, SIZE);
  92             renderPattern(bimg2.createGraphics());
  93 
  94             vimg = createVolatileImage(SIZE, SIZE);
  95             vimg.validate(getGraphicsConfiguration());
  96             renderPattern(vimg.createGraphics());
  97         }
  98 
  99         do {
 100             g2d.setColor(Color.white);
 101             g2d.fillRect(0, 0, getWidth(), getHeight());
 102 
 103             g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
 104                                  RenderingHints.VALUE_INTERPOLATION_BILINEAR);
 105 
 106             // first time will be a sw->surface blit
 107             g2d.drawImage(bimg1, 10, 10, 40, 40, null);
 108 
 109             // second time will be a texture->surface blit
 110             g2d.drawImage(bimg2, 80, 10, 40, 40, null);
 111             if (!skipOglTextureTest) {
 112                 g2d.drawImage(bimg2, 80, 10, 40, 40, null);
 113             }
 114 
 115             // third time will be a pbuffer->surface blit
 116             if (vimg.validate(getGraphicsConfiguration()) != VolatileImage.IMAGE_OK) {
 117                 renderPattern(vimg.createGraphics());
 118             }
 119             g2d.drawImage(vimg, 150, 10, 40, 40, null);
 120 
 121             Toolkit.getDefaultToolkit().sync();
 122         } while (vimg.contentsLost());
 123 
 124         synchronized (this) {
 125             if (!done) {
 126                 doCapture(this);
 127                 done = true;
 128             }
 129             notifyAll();
 130         }
 131     }
 132 
 133     public Dimension getPreferredSize() {
 134         return new Dimension(200, 100);
 135     }
 136 
 137     private static void testRegion(BufferedImage bi,
 138                                    Rectangle affectedRegion)
 139     {
 140         int x1 = affectedRegion.x;
 141         int y1 = affectedRegion.y;
 142         int x2 = x1 + affectedRegion.width;
 143         int y2 = y1 + affectedRegion.height;
 144 
 145         for (int y = y1; y < y2; y++) {
 146             for (int x = x1; x < x2; x++) {
 147                 int actual = bi.getRGB(x, y);
 148                 if ((actual != 0xfffe0000) && (actual != 0xffff0000)) {
 149                     throw new RuntimeException("Test failed at x="+x+" y="+y+
 150                                                " (expected=0xffff0000"+
 151                                                " actual=0x"+
 152                                                Integer.toHexString(actual) +
 153                                                ")");
 154                 }
 155             }
 156         }
 157     }
 158 
 159     private static boolean skipOglTextureTest = false;
 160 
 161     public static void main(String[] args) {
 162         boolean show = false;
 163         for (String arg : args) {
 164             if ("-show".equals(arg)) {
 165                 show = true;
 166             }
 167         }
 168 
 169         String arch = System.getProperty("os.arch");
 170         boolean isOglEnabled = Boolean.getBoolean("sun.java2d.opengl");
 171         skipOglTextureTest = isOglEnabled && ("sparc".equals(arch));
 172         System.out.println("Skip OpenGL texture test: " + skipOglTextureTest);
 173 
 174         DrawImageBilinear test = new DrawImageBilinear();
 175         Frame frame = new Frame();
 176         frame.add(test);
 177         frame.pack();
 178         frame.setVisible(true);
 179 
 180         // Wait until the component's been painted
 181         synchronized (test) {
 182             while (!done) {
 183                 try {
 184                     test.wait();
 185                 } catch (InterruptedException e) {
 186                     throw new RuntimeException("Failed: Interrupted");
 187                 }
 188             }
 189         }
 190 
 191         GraphicsConfiguration gc = frame.getGraphicsConfiguration();
 192         if (gc.getColorModel() instanceof IndexColorModel) {
 193             System.out.println("IndexColorModel detected: " +
 194                                "test considered PASSED");
 195             frame.dispose();
 196             return;
 197         }
 198 
 199         if (!show) {
 200             frame.dispose();
 201         }
 202         if (capture == null) {
 203             throw new RuntimeException("Failed: capture is null");
 204         }
 205 
 206         // Test background color
 207         int pixel = capture.getRGB(5, 5);
 208         if (pixel != 0xffffffff) {
 209             throw new RuntimeException("Failed: Incorrect color for " +
 210                                        "background");
 211         }
 212 
 213         // Test pixels
 214         testRegion(capture, new Rectangle(10, 10, 40, 40));
 215         testRegion(capture, new Rectangle(80, 10, 40, 40));
 216         testRegion(capture, new Rectangle(150, 10, 40, 40));
 217     }
 218 }