/*
* Copyright (c) 2010, 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.
*/
/*
@test
@bug 5089429 6982632
@summary Checks that we don't crash if rendering operations and state
changes are performed on a graphics context from different threads.
@author Dmitri.Trembovetski@sun.com area=Graphics
@run main MTGraphicsAccessTest
*/
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
public class MTGraphicsAccessTest {
// in seconds
static final long STANDALONE_RUN_TIME = 20;
static final long JTREG_RUN_TIME = 7;
static boolean standaloneMode;
static boolean allowExceptions = true;
static long testRunTime;
volatile boolean done;
volatile int stillRunning;
volatile int numexceptions;
Graphics2D sharedGraphics;
BufferedImage sharedBI =
new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB);
static final Paint colors[] = {
Color.red,
new Color(0x7f, 0xff, 0x00, 0x7f),
new GradientPaint(0, 0, Color.red,
50, 50, new Color(0x7f, 0xff, 0x00, 0x7f)),
};
static final Font fonts[] = {
new Font("Dialog", Font.PLAIN, 12),
new Font("Dialog", Font.BOLD, 16),
new Font("Dialog", Font.ITALIC, 18),
};
static final AlphaComposite comps[] = {
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f),
AlphaComposite.Src,
AlphaComposite.Xor,
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f),
null,
};
static final Stroke strokes[] = {
new BasicStroke(),
new BasicStroke(0.0f),
new BasicStroke(2.0f),
new BasicStroke(2.0f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_BEVEL),
new BasicStroke(5.0f, BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_ROUND),
new BasicStroke(0.0f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND, 0,
new float[]{0,6,0,6}, 0),
};
static final AffineTransform transforms[] = {
new AffineTransform(),
AffineTransform.getRotateInstance(10.0),
AffineTransform.getShearInstance(10.0, 4.0),
AffineTransform.getScaleInstance(1.1, 1.2),
AffineTransform.getScaleInstance(3.0, 2.0),
};
public MTGraphicsAccessTest() {
BufferedImage bi =
new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB);
sharedGraphics = (Graphics2D)bi.getGraphics();
done = false;
numexceptions = 0;
for (int i = 0; i < (standaloneMode ? stateChangers.length : 3); i++) {
(new TesterThread(stateChangers[i])).start();
}
for (int i = 0; i < (standaloneMode ? renderTests.length : 5); i++) {
(new TesterThread(renderTests[i])).start();
}
mysleep(testRunTime);
done = true;
while (stillRunning > 0) { mysleep(500); }
if (numexceptions == 0) {
System.err.println("Test passed");
} else if (!allowExceptions) {
throw new RuntimeException("Test failed with "+
numexceptions+" exceptions");
} else {
System.err.println("Test finished with "+
numexceptions+" exceptions");
}
}
private void mysleep(long time) {
try {
// add +/-5ms variance to increase randomness
Thread.sleep(time + (long)(5 - Math.random()*10));
} catch (InterruptedException e) {};
}
public static void usage(String message) {
if (message != null) {
System.err.println(message);
}
System.err.println("Usage: MTGraphicsAccessTest [-full] "+
"[-time N/forever] [-help]");
System.err.println(" -full: run full suite of tests "+
"(default: limited number of tests is run)");
System.err.println(" -time N: test duration in seconds/forever"+
" (default: "+JTREG_RUN_TIME+"s for the short suite, "+
STANDALONE_RUN_TIME+"s for the full suite)");
System.err.println(" -help: print this help page");
System.exit(1);
}
public static void main(String[] args) {
boolean testRunSet = false;
for (int i = 0; i < args.length; i++) {
if ("-full".equals(args[i])) {
standaloneMode = true;
System.err.println("Running complete list of tests");
} else if ("-noexc".equals(args[i])) {
allowExceptions = false;
} else if ("-time".equals(args[i])) {
try {
String time = args[++i];
if ("forever".equals(time)) {
testRunTime = (Long.MAX_VALUE - 20)/1000;
} else {
testRunTime = 1000*Integer.parseInt(time);
}
testRunSet = true;
} catch (NumberFormatException e) {
usage("Can't parse number of seconds: " + args[i]);
} catch (ArrayIndexOutOfBoundsException e1) {
usage("Missing the 'seconds' argument for -time parameter");
}
} else if ("-help".equals(args[i])) {
usage(null);
} else {
usage("Unknown argument:" + args[i]);
}
}
if (!testRunSet) {
testRunTime = 1000 *
(standaloneMode ? STANDALONE_RUN_TIME : JTREG_RUN_TIME);
}
System.err.println("Approximate test run time: "+
testRunTime/1000+" seconds");
new MTGraphicsAccessTest();
}
class TesterThread extends Thread {
Runnable testRunnable;
public TesterThread(Runnable testRunnable) {
stillRunning++;
this.testRunnable = testRunnable;
}
public void run() {
try {
while (!done) {
try {
testRunnable.run();
yield();
} catch (Throwable t) {
numexceptions++;
t.printStackTrace();
}
}
} finally {
stillRunning--;
}
}
}
final Runnable stateChangers[] = {
new Runnable() {
public void run() {
sharedGraphics.setClip(10, 10, 30, 30);
mysleep(10);
}
},
new Runnable() {
public void run() {
sharedGraphics.setClip(10, 10, 30, 30);
mysleep(10);
}
},
new Runnable() {
int c = 0;
public void run() {
sharedGraphics.setPaint(colors[c++ % colors.length]);
mysleep(10);
}
},
new Runnable() {
boolean AA = false;
public void run() {
if (AA) {
sharedGraphics.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
} else {
sharedGraphics.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
}
AA = !AA;
mysleep(10);
}
},
new Runnable() {
int t = 0;
public void run() {
sharedGraphics.setTransform(
transforms[t++ % transforms.length]);
mysleep(10);
}
},
new Runnable() {
int c = 0;
public void run() {
AlphaComposite comp = comps[c++ % comps.length];
if (comp == null) {
sharedGraphics.setXORMode(Color.green);
} else {
sharedGraphics.setComposite(comp);
}
mysleep(10);
}
},
new Runnable() {
int s = 0;
public void run() {
sharedGraphics.setStroke(strokes[s++ % strokes.length]);
mysleep(10);
}
},
new Runnable() {
int f = 0;
public void run() {
sharedGraphics.setFont(fonts[f++ % fonts.length]);
mysleep(10);
}
},
};
final Runnable renderTests[] = {
new Runnable() {
public void run() {
sharedGraphics.drawLine(10, 10, 30, 30);
}
},
new Runnable() {
public void run() {
sharedGraphics.drawLine(10, 10, 30, 30);
}
},
new Runnable() {
public void run() {
sharedGraphics.drawRect(10, 10, 30, 30);
}
},
new Runnable() {
public void run() {
sharedGraphics.fillRect(10, 10, 30, 30);
}
},
new Runnable() {
public void run() {
sharedGraphics.drawString("Stuff", 10, 10);
}
},
new Runnable() {
public void run() {
sharedGraphics.draw3DRect(10, 10, 30, 30, true);
}
},
new Runnable() {
public void run() {
sharedGraphics.drawImage(sharedBI, 10, 10, null);
}
},
new Runnable() {
public void run() {
sharedGraphics.fill3DRect(10, 10, 30, 30, false);
}
},
// REMIND: copyArea doesn't work when transform is set..
// new Runnable() {
// public void run() {
// sharedGraphics.copyArea(10, 10, 30, 30, 20, 20);
// }
// },
new Runnable() {
public void run() {
sharedGraphics.drawRoundRect(10, 10, 30, 30, 20, 20);
}
},
new Runnable() {
public void run() {
sharedGraphics.fillRoundRect(10, 10, 30, 30, 20, 20);
}
},
new Runnable() {
public void run() {
sharedGraphics.drawArc(10, 10, 30, 30, 0, 90);
}
},
new Runnable() {
public void run() {
sharedGraphics.fillArc(10, 10, 30, 30, 0, 90);
}
},
new Runnable() {
public void run() {
sharedGraphics.drawOval(10, 10, 30, 30);
}
},
new Runnable() {
public void run() {
sharedGraphics.fillOval(10, 10, 30, 30);
}
}
};
}