blob: 60f6cccd8647ab1e54c91d74f54b0db5caa0efb7 [file] [log] [blame]
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.AWTException;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.VolatileImage;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import javax.imageio.ImageIO;
import sun.awt.ConstrainableGraphics;
/**
* @test
* @bug 6335200 6419610
* @summary Tests that we don't render anything if specific empty clip is set
* @author Dmitri.Trembovetski@Sun.COM: area=Graphics
* @modules java.desktop/sun.awt
* @run main EmptyClipRenderingTest
* @run main/othervm -Dsun.java2d.noddraw=true EmptyClipRenderingTest
* @run main/othervm -Dsun.java2d.pmoffscreen=true EmptyClipRenderingTest
* @run main/othervm -Dsun.java2d.opengl=true EmptyClipRenderingTest
*/
public class EmptyClipRenderingTest {
static final int IMG_W = 400;
static final int IMG_H = 400;
// generated rectangles
static HashSet<Rectangle> rects;
volatile boolean isActivated = false;
volatile boolean isPainted;
private static boolean showErrors = false;
public EmptyClipRenderingTest() {
// initialize clip/render region rectangles
initClips();
HashSet<RuntimeException> errors = new HashSet<RuntimeException>();
BufferedImage screenResult = testOnscreen();
try {
testResult(screenResult, "Screen");
} catch (RuntimeException e) {
errors.add(e);
}
BufferedImage destBI =
new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_RGB);
runTest((Graphics2D)destBI.getGraphics());
try {
testResult(destBI, "BufferedImage");
} catch (RuntimeException e) {
errors.add(e);
}
GraphicsConfiguration gc =
GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().getDefaultConfiguration();
VolatileImage destVI = gc.createCompatibleVolatileImage(IMG_W, IMG_H);
destVI.validate(gc);
runTest((Graphics2D)destVI.getGraphics());
try {
testResult(destVI.getSnapshot(), "VolatileImage");
} catch (RuntimeException e) {
errors.add(e);
}
if (errors.isEmpty()) {
System.err.println("Test PASSED.");
} else {
for (RuntimeException re : errors) {
re.printStackTrace();
}
if (showErrors) {
System.err.println("Test FAILED: "+ errors.size() +
" subtest failures.");
} else {
throw new RuntimeException("Test FAILED: "+ errors.size() +
" subtest failures.");
}
}
}
/**
* Recursively adds 4 new rectangles: two vertical and two horizontal
* based on the passed rectangle area. The area is then shrunk and the
* process repeated for smaller area.
*/
private static void add4Rects(HashSet<Rectangle> rects, Rectangle area) {
if (area.width < 10 || area.height < 10) {
rects.add(area);
return;
}
// two vertical rects
rects.add(new Rectangle(area.x, area.y, 5, area.height));
rects.add(new Rectangle(area.x + area.width - 5, area.y, 5, area.height));
// two horizontal rects
int width = area.width - 2*(5 + 1);
rects.add(new Rectangle(area.x+6, area.y, width, 5));
rects.add(new Rectangle(area.x+6, area.y + area.height - 5, width, 5));
// reduce the area and repeat
area.grow(-6, -6);
add4Rects(rects, area);
}
/**
* Generate a bunch of non-intersecting rectangles
*/
private static void initClips() {
rects = new HashSet<Rectangle>();
add4Rects(rects, new Rectangle(0, 0, IMG_W, IMG_H));
System.err.println("Total number of test rects: " + rects.size());
}
/**
* Render the pattern to the screen, capture the output with robot and
* return it.
*/
private BufferedImage testOnscreen() throws HeadlessException {
final Canvas destComponent;
final Object lock = new Object();
Frame f = new Frame("Test Frame");
f.setUndecorated(true);
f.add(destComponent = new Canvas() {
public void paint(Graphics g) {
isPainted = true;
}
public Dimension getPreferredSize() {
return new Dimension(IMG_W, IMG_H);
}
});
f.addWindowListener(new WindowAdapter() {
public void windowActivated(WindowEvent e) {
if (!isActivated) {
synchronized (lock) {
isActivated = true;
lock.notify();
}
}
}
});
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
synchronized(lock) {
while (!isActivated) {
try {
lock.wait(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
Robot r;
try {
r = new Robot();
} catch (AWTException ex) {
throw new RuntimeException("Can't create Robot");
}
BufferedImage bi;
int attempt = 0;
do {
if (++attempt > 10) {
throw new RuntimeException("Too many attempts: " + attempt);
}
isPainted = false;
runTest((Graphics2D) destComponent.getGraphics());
r.waitForIdle();
Toolkit.getDefaultToolkit().sync();
bi = r.createScreenCapture(
new Rectangle(destComponent.getLocationOnScreen().x,
destComponent.getLocationOnScreen().y,
destComponent.getWidth(),
destComponent.getHeight()));
} while (isPainted);
f.setVisible(false);
f.dispose();
return bi;
}
/**
* Run the test: cycle through all the rectangles, use one as clip and
* another as the area to render to.
* Set the clip in the same way Swing does it when repainting:
* first constrain the graphics to the damaged area, and repaint everything
*/
void runTest(Graphics2D destGraphics) {
destGraphics.setColor(Color.black);
destGraphics.fillRect(0, 0, IMG_W, IMG_H);
destGraphics.setColor(Color.red);
for (Rectangle clip : rects) {
Graphics2D g2d = (Graphics2D)destGraphics.create();
g2d.setColor(Color.red);
// mimic what swing does in BufferStrategyPaintManager
if (g2d instanceof ConstrainableGraphics) {
((ConstrainableGraphics)g2d).constrain(clip.x, clip.y,
clip.width, clip.height);
}
g2d.setClip(clip);
for (Rectangle renderRegion : rects) {
if (renderRegion != clip) {
// from CellRendererPane's paintComponent
Graphics2D rG = (Graphics2D)
g2d.create(renderRegion.x, renderRegion.y,
renderRegion.width, renderRegion.height);
rG.fillRect(0,0, renderRegion.width, renderRegion.height);
}
}
}
}
void testResult(final BufferedImage bi, final String desc) {
for (int y = 0; y < bi.getHeight(); y++) {
for (int x = 0; x < bi.getWidth(); x++) {
if (bi.getRGB(x, y) != Color.black.getRGB()) {
if (showErrors) {
Frame f = new Frame("Error: " + desc);
f.add(new Component() {
public void paint(Graphics g) {
g.drawImage(bi, 0, 0, null);
}
public Dimension getPreferredSize() {
return new Dimension(bi.getWidth(),
bi.getHeight());
}
});
f.pack();
f.setVisible(true);
}
try {
String fileName =
"EmptyClipRenderingTest_"+desc+"_res.png";
System.out.println("Writing resulting image: "+fileName);
ImageIO.write(bi, "png", new File(fileName));
} catch (IOException ex) {
ex.printStackTrace();
}
throw new RuntimeException("Dest: "+desc+
" was rendered to at x="+
x + " y=" + y +
" pixel="+Integer.toHexString(bi.getRGB(x,y)));
}
}
}
}
public static void main(String argv[]) {
for (String arg : argv) {
if (arg.equals("-show")) {
showErrors = true;
} else {
usage("Incorrect argument:" + arg);
}
}
new EmptyClipRenderingTest();
}
private static void usage(String string) {
System.out.println(string);
System.out.println("Usage: EmptyClipRenderingTest [-show]");
}
}