undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2002, 2024, 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 4532352
* @summary This test verifies that the specified background color is rendered
* in the special case of:
* Graphics.drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
* int sx1, int sy1, int sx2, int sy2,
* Color bgColor, ImageObserver observer)
* where no scaling takes place because the source and destination
* bounds have the same width and height.
*/
import java.io.File;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class DrawImageBgTest {
public static void main(String argv[]) throws Exception {
int dx, dy, dw, dh;
int sx, sy, sw, sh;
int iw = 250, ih = 250;
String sep = System.getProperty("file.separator");
String dir = System.getProperty("test.src", ".");
String prefix = dir+sep;
BufferedImage img = ImageIO.read(new File(prefix + "duke.gif"));
BufferedImage dest = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
Graphics2D g = dest.createGraphics();
g.setColor(Color.blue);
g.fillRect(0, 0, iw, ih);
// source and destination dimensions are different, results in scaling
dx = 10;
dy = 10;
dw = 100;
dh = 200;
sx = 10;
sy = 10;
sw = 50;
sh = 100;
g.drawImage(img,
dx, dy, dx + dw, dy + dh,
sx, sy, sx + sw, sy + sh,
Color.yellow, null);
int pix1 = dest.getRGB(dx + 1, dy + 1);
// source and destination dimensions are the same, no scaling
dx = 120;
dy = 10;
sx = 10;
sy = 10;
sw = dw = 50;
sh = dh = 100;
g.drawImage(img,
dx, dy, dx + dw, dy + dh,
sx, sy, sx + sw, sy + sh,
Color.yellow, null);
int pix2 = dest.getRGB(dx + 1, dy + 1);
int yellow = Color.yellow.getRGB();
if (pix1 != yellow || pix2 != yellow) {
ImageIO.write(dest, "gif", new File("op.gif"));
throw new RuntimeException("pix1=" + Integer.toHexString(pix1) +
" pix2=" + Integer.toHexString(pix2));
}
}
}

View file

@ -0,0 +1,192 @@
/*
* Copyright (c) 2012, 2020, 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
* @key headful
* @bug 7188093 8000176 8198613
* @summary Tests each of the 3 possible methods for rendering an upscaled
* image via rendering hints for default, xrender and opengl pipelines.
*
* @run main/othervm -Dsun.java2d.uiScale=1 -Dsun.java2d.xrender=false InterpolationQualityTest
* @run main/othervm -Dsun.java2d.uiScale=1 -Dsun.java2d.xrender=True InterpolationQualityTest
* @run main/othervm -Dsun.java2d.uiScale=1 -Dsun.java2d.d3d=false InterpolationQualityTest
* @run main/othervm -Dsun.java2d.uiScale=1 -Dsun.java2d.d3d=True InterpolationQualityTest
* @run main/othervm -Dsun.java2d.uiScale=1 InterpolationQualityTest
*/
import java.awt.*;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class InterpolationQualityTest {
private static final int testSize = 4, scaleFactor = 20, tolerance = 3;
private static final int sw = testSize * scaleFactor;
private static final int sh = testSize * scaleFactor;
private Image testImage;
private VolatileImage vImg;
public InterpolationQualityTest() {
testImage = createTestImage();
}
private Image createTestImage() {
BufferedImage bi = new BufferedImage(testSize, testSize, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, testSize, testSize);
for (int i = 0; i < testSize; i++) {
bi.setRGB(i, i, Color.WHITE.getRGB());
}
return bi;
}
private BufferedImage createReferenceImage(Object hint) {
BufferedImage bi = new BufferedImage(sw, sh, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
drawImage(g2d, hint);
return bi;
}
private void drawImage(Graphics2D g2d, Object hint) {
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2d.drawImage(testImage, 0, 0, sw, sh, null);
}
private GraphicsConfiguration getDefaultGC() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().getDefaultConfiguration();
}
private void createVImg() {
vImg = getDefaultGC().createCompatibleVolatileImage(sw, sh);
}
private void renderOffscreen(Object hint) {
Graphics2D g = vImg.createGraphics();
drawImage(g, hint);
g.dispose();
}
private BufferedImage renderImage(Object hint) {
BufferedImage snapshot;
createVImg();
renderOffscreen(hint);
do {
int status = vImg.validate(getDefaultGC());
if (status != VolatileImage.IMAGE_OK) {
if (status == VolatileImage.IMAGE_INCOMPATIBLE) {
createVImg();
}
renderOffscreen(hint);
}
snapshot = vImg.getSnapshot();
} while (vImg.contentsLost());
vImg.flush();
return snapshot;
}
private boolean compareComponent(int comp1, int comp2) {
return Math.abs(comp1 - comp2) <= tolerance;
}
private boolean compareRGB(int rgb1, int rgb2) {
Color col1 = new Color(rgb1);
Color col2 = new Color(rgb2);
return compareComponent(col1.getRed(), col2.getRed()) &&
compareComponent(col1.getBlue(), col2.getBlue()) &&
compareComponent(col1.getGreen(), col2.getGreen()) &&
compareComponent(col1.getAlpha(), col2.getAlpha());
}
private boolean compareImages(BufferedImage img, BufferedImage ref, String imgName) {
for (int y = 0; y < ref.getHeight(); y++) {
for (int x = 0; x < ref.getWidth(); x++) {
if (!compareRGB(ref.getRGB(x, y), img.getRGB(x, y))) {
System.out.println(imgName + ".getRGB(" + x + ", " + y + ") = "
+ new Color(img.getRGB(x, y)) + " != "
+ new Color(ref.getRGB(x, y)));
return false;
}
}
}
return true;
}
private boolean test(Object hint) {
BufferedImage refImage = createReferenceImage(hint);
BufferedImage resImage = renderImage(hint);
boolean passed = compareImages(resImage, refImage, "resImage");
System.out.println(getHintName(hint) + (passed ? " passed." : " failed."));
if (!passed) {
dumpImage(refImage, "out_" + getHintName(hint) + "_ref.png");
dumpImage(resImage, "out_" + getHintName(hint) + ".png");
}
return passed;
}
public void test() {
boolean passed = true;
passed &= test(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
passed &= test(RenderingHints.VALUE_INTERPOLATION_BILINEAR);
passed &= test(RenderingHints.VALUE_INTERPOLATION_BICUBIC);
if (passed) {
System.out.println("Test PASSED.");
} else {
throw new RuntimeException("Test FAILED.");
}
}
private String getHintName(Object hint) {
if (hint == RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR) {
return "nearest";
}
else if (hint == RenderingHints.VALUE_INTERPOLATION_BILINEAR) {
return "bilinear";
}
else if (hint == RenderingHints.VALUE_INTERPOLATION_BICUBIC) {
return "bicubic";
}
else {
return "null";
}
}
private void dumpImage(BufferedImage bi, String name) {
try {
ImageIO.write(bi, "PNG", new File(name));
} catch (IOException ex) {
}
}
public static void main(String[] argv) {
InterpolationQualityTest test = new InterpolationQualityTest();
test.test();
}
}

View file

@ -0,0 +1,189 @@
/*
* Copyright (c) 2007, 2018, 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
* @key headful
* @bug 6613860 6691934 8198613
* @summary Tests that the pipelines can handle (in somewhat limited
* manner) mutable Colors
*
* @run main/othervm MutableColorTest
* @run main/othervm -Dsun.java2d.noddraw=true MutableColorTest
*/
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.awt.image.VolatileImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class MutableColorTest {
static Image bmImage;
static Image argbImage;
static class EvilColor extends Color {
Color colors[] = { Color.red, Color.green, Color.blue };
int currentIndex = 0;
EvilColor() {
super(Color.red.getRGB());
}
@Override
public int getRGB() {
return colors[currentIndex].getRGB();
}
void nextColor() {
currentIndex++;
}
}
private static int testImage(Image im,
boolean doClip, boolean doTx)
{
int w = im.getWidth(null);
int h = im.getHeight(null);
Graphics2D g = (Graphics2D)im.getGraphics();
EvilColor evilColor = new EvilColor();
g.setColor(evilColor);
g.fillRect(0, 0, w, h);
g.dispose();
evilColor.nextColor();
g = (Graphics2D)im.getGraphics();
if (doTx) {
g.rotate(Math.PI/2.0, w/2, h/2);
}
g.setColor(evilColor);
g.fillRect(0, 0, w, h);
if (doClip) {
g.clip(new Ellipse2D.Float(0, 0, w, h));
}
g.fillRect(0, h/3, w, h/3);
// tests native BlitBg loop
g.drawImage(bmImage, 0, 2*h/3, evilColor, null);
// tests General BlitBg loop
g.drawImage(argbImage, 0, 2*h/3+h/3/2, evilColor, null);
return evilColor.getRGB();
}
private static void testResult(final String desc,
final BufferedImage snapshot,
final int evilColor) {
for (int y = 0; y < snapshot.getHeight(); y++) {
for (int x = 0; x < snapshot.getWidth(); x++) {
int snapRGB = snapshot.getRGB(x, y);
if (!isSameColor(snapRGB, evilColor)) {
System.err.printf("Wrong RGB for %s at (%d,%d): 0x%x " +
"instead of 0x%x\n", desc, x, y, snapRGB, evilColor);
String fileName = "MutableColorTest_"+desc+".png";
try {
ImageIO.write(snapshot, "png", new File(fileName));
System.err.println("Dumped snapshot to "+fileName);
} catch (IOException ex) {}
throw new RuntimeException("Test FAILED.");
}
}
}
}
public static void main(String[] args) {
GraphicsConfiguration gc =
GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().getDefaultConfiguration();
bmImage = gc.createCompatibleImage(64, 64, Transparency.BITMASK);
argbImage = gc.createCompatibleImage(64, 64, Transparency.TRANSLUCENT);
if (gc.getColorModel().getPixelSize() > 8) {
VolatileImage vi =
gc.createCompatibleVolatileImage(64, 64, Transparency.OPAQUE);
do {
if (vi.validate(gc) == VolatileImage.IMAGE_INCOMPATIBLE) {
vi = gc.createCompatibleVolatileImage(64, 64,
Transparency.OPAQUE);
vi.validate(gc);
}
int color = testImage(vi, false, false);
testResult("vi_noclip_notx", vi.getSnapshot(), color);
color = testImage(vi, true, true);
testResult("vi_clip_tx", vi.getSnapshot(), color);
color = testImage(vi, true, false);
testResult("vi_clip_notx", vi.getSnapshot(), color);
color = testImage(vi, false, true);
testResult("vi_noclip_tx", vi.getSnapshot(), color);
} while (vi.contentsLost());
}
BufferedImage bi = new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB);
int color = testImage(bi, false, false);
testResult("bi_noclip_notx", bi, color);
color = testImage(bi, true, true);
testResult("bi_clip_tx", bi, color);
color = testImage(bi, true, false);
testResult("bi_clip_notx", bi, color);
color = testImage(bi, false, true);
testResult("bi_noclip_tx", bi, color);
System.err.println("Test passed.");
}
/*
* We assume that colors with slightly different components
* are the same. This is done just in order to workaround
* peculiarities of OGL rendering pipeline on some platforms.
* See CR 6989217 for more details.
*/
private static boolean isSameColor(int color1, int color2) {
final int tolerance = 2;
for (int i = 0; i < 32; i += 8) {
int c1 = 0xff & (color1 >> i);
int c2 = 0xff & (color2 >> i);
if (Math.abs(c1 - c2) > tolerance) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,534 @@
/*
* Copyright (c) 2009, 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.
*/
/*
* @test %W% %E%
* @bug 6504874
* @summary This test verifies the operation (and performance) of the
* various CAG operations on the internal Region class.
* @modules java.desktop/sun.java2d.pipe
* @run main RegionOps
*/
import java.awt.Rectangle;
import java.awt.geom.Area;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Random;
import sun.java2d.pipe.Region;
public class RegionOps {
public static final int DEFAULT_NUMREGIONS = 50;
public static final int DEFAULT_MINSUBRECTS = 1;
public static final int DEFAULT_MAXSUBRECTS = 10;
public static final int MINCOORD = -20;
public static final int MAXCOORD = 20;
public static boolean useArea;
static int numops;
static int numErrors;
static Random rand = new Random();
static boolean skipCheck;
static boolean countErrors;
static {
// Instantiating BufferedImage initializes sun.java2d
BufferedImage bimg =
new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
}
public static void usage(String error) {
if (error != null) {
System.err.println("Error: "+error);
}
System.err.println("Usage: java RegionOps "+
"[-regions N] [-rects M] "+
"[-[min|max]rects M] [-area]");
System.err.println(" "+
"[-add|union] [-sub|diff] "+
"[-int[ersect]] [-xor]");
System.err.println(" "+
"[-seed S] [-nocheck] [-count[errors]] [-help]");
System.exit((error != null) ? 1 : 0);
}
public static void error(RectListImpl a, RectListImpl b, String problem) {
System.err.println("Operating on: "+a);
if (b != null) {
System.err.println("and: "+b);
}
if (countErrors) {
System.err.println(problem);
numErrors++;
} else {
throw new RuntimeException(problem);
}
}
public static void main(String argv[]) {
int numregions = DEFAULT_NUMREGIONS;
int minsubrects = DEFAULT_MINSUBRECTS;
int maxsubrects = DEFAULT_MAXSUBRECTS;
boolean doUnion = false;
boolean doIntersect = false;
boolean doSubtract = false;
boolean doXor = false;
for (int i = 0; i < argv.length; i++) {
String arg = argv[i];
if (arg.equalsIgnoreCase("-regions")) {
if (i+1 >= argv.length) {
usage("missing arg for -regions");
}
numregions = Integer.parseInt(argv[++i]);
} else if (arg.equalsIgnoreCase("-rects")) {
if (i+1 >= argv.length) {
usage("missing arg for -rects");
}
minsubrects = maxsubrects = Integer.parseInt(argv[++i]);
} else if (arg.equalsIgnoreCase("-minrects")) {
if (i+1 >= argv.length) {
usage("missing arg for -minrects");
}
minsubrects = Integer.parseInt(argv[++i]);
} else if (arg.equalsIgnoreCase("-maxrects")) {
if (i+1 >= argv.length) {
usage("missing arg for -maxrects");
}
maxsubrects = Integer.parseInt(argv[++i]);
} else if (arg.equalsIgnoreCase("-area")) {
useArea = true;
} else if (arg.equalsIgnoreCase("-add") ||
arg.equalsIgnoreCase("-union"))
{
doUnion = true;
} else if (arg.equalsIgnoreCase("-sub") ||
arg.equalsIgnoreCase("-diff"))
{
doSubtract = true;
} else if (arg.equalsIgnoreCase("-int") ||
arg.equalsIgnoreCase("-intersect"))
{
doIntersect = true;
} else if (arg.equalsIgnoreCase("-xor")) {
doXor = true;
} else if (arg.equalsIgnoreCase("-seed")) {
if (i+1 >= argv.length) {
usage("missing arg for -seed");
}
rand.setSeed(Long.decode(argv[++i]).longValue());
} else if (arg.equalsIgnoreCase("-nocheck")) {
skipCheck = true;
} else if (arg.equalsIgnoreCase("-count") ||
arg.equalsIgnoreCase("-counterrors"))
{
countErrors = true;
} else if (arg.equalsIgnoreCase("-help")) {
usage(null);
} else {
usage("Unknown argument: "+arg);
}
}
if (maxsubrects < minsubrects) {
usage("maximum number of subrectangles less than minimum");
}
if (minsubrects <= 0) {
usage("minimum number of subrectangles must be positive");
}
if (!doUnion && !doSubtract && !doIntersect && !doXor) {
doUnion = doSubtract = doIntersect = doXor = true;
}
long start = System.currentTimeMillis();
RectListImpl rlist[] = new RectListImpl[numregions];
int totalrects = 0;
for (int i = 0; i < rlist.length; i++) {
RectListImpl rli = RectListImpl.getInstance();
int numsubrects =
minsubrects + rand.nextInt(maxsubrects - minsubrects + 1);
for (int j = 0; j < numsubrects; j++) {
addRectTo(rli);
totalrects++;
}
rlist[i] = rli;
}
long end = System.currentTimeMillis();
System.out.println((end-start)+"ms to create "+
rlist.length+" regions containing "+
totalrects+" subrectangles");
start = System.currentTimeMillis();
for (int i = 0; i < rlist.length; i++) {
RectListImpl a = rlist[i];
testTranslate(a);
for (int j = i; j < rlist.length; j++) {
RectListImpl b = rlist[j];
if (doUnion) testUnion(a, b);
if (doSubtract) testDifference(a, b);
if (doIntersect) testIntersection(a, b);
if (doXor) testExclusiveOr(a, b);
}
}
end = System.currentTimeMillis();
System.out.println(numops+" ops took "+(end-start)+"ms");
if (numErrors > 0) {
throw new RuntimeException(numErrors+" errors encountered");
}
}
public static void addRectTo(RectListImpl rli) {
int lox = MINCOORD + rand.nextInt(MAXCOORD - MINCOORD + 1);
int hix = MINCOORD + rand.nextInt(MAXCOORD - MINCOORD + 1);
int loy = MINCOORD + rand.nextInt(MAXCOORD - MINCOORD + 1);
int hiy = MINCOORD + rand.nextInt(MAXCOORD - MINCOORD + 1);
rli.addRect(lox, loy, hix, hiy);
}
public static void checkEqual(RectListImpl a, RectListImpl b,
String optype)
{
if (a.hashCode() != b.hashCode()) {
error(a, b, "hashcode failed for "+optype);
}
if (!a.equals(b)) {
error(a, b, "equals failed for "+optype);
}
}
public static void testTranslate(RectListImpl a) {
RectListImpl maxTrans =
a.getTranslation(Integer.MAX_VALUE, Integer.MAX_VALUE)
.getTranslation(Integer.MAX_VALUE, Integer.MAX_VALUE)
.getTranslation(Integer.MAX_VALUE, Integer.MAX_VALUE);
if (!maxTrans.checkTransEmpty()) {
error(maxTrans, null, "overflow translated RectList not empty");
}
RectListImpl minTrans =
a.getTranslation(Integer.MIN_VALUE, Integer.MIN_VALUE)
.getTranslation(Integer.MIN_VALUE, Integer.MIN_VALUE)
.getTranslation(Integer.MIN_VALUE, Integer.MIN_VALUE);
if (!minTrans.checkTransEmpty()) {
error(minTrans, null, "overflow translated RectList not empty");
}
testTranslate(a, Integer.MAX_VALUE, Integer.MAX_VALUE, false,
MINCOORD, 0, MINCOORD, 0);
testTranslate(a, Integer.MAX_VALUE, Integer.MIN_VALUE, false,
MINCOORD, 0, 0, MAXCOORD);
testTranslate(a, Integer.MIN_VALUE, Integer.MAX_VALUE, false,
0, MAXCOORD, MINCOORD, 0);
testTranslate(a, Integer.MIN_VALUE, Integer.MIN_VALUE, false,
0, MAXCOORD, 0, MAXCOORD);
for (int dy = -100; dy <= 100; dy += 50) {
for (int dx = -100; dx <= 100; dx += 50) {
testTranslate(a, dx, dy, true,
MINCOORD, MAXCOORD,
MINCOORD, MAXCOORD);
}
}
}
public static void testTranslate(RectListImpl a, int dx, int dy,
boolean isNonDestructive,
int xmin, int xmax,
int ymin, int ymax)
{
RectListImpl theTrans = a.getTranslation(dx, dy); numops++;
if (skipCheck) return;
RectListImpl unTrans = theTrans.getTranslation(-dx, -dy);
if (isNonDestructive) checkEqual(a, unTrans, "Translate");
for (int x = xmin; x < xmax; x++) {
for (int y = ymin; y < ymax; y++) {
boolean inside = a.contains(x, y);
if (theTrans.contains(x+dx, y+dy) != inside) {
error(a, null, "translation failed for "+
dx+", "+dy+" at "+x+", "+y);
}
}
}
}
public static void testUnion(RectListImpl a, RectListImpl b) {
RectListImpl aUb = a.getUnion(b); numops++;
RectListImpl bUa = b.getUnion(a); numops++;
if (skipCheck) return;
checkEqual(aUb, bUa, "Union");
testUnion(a, b, aUb);
testUnion(a, b, bUa);
}
public static void testUnion(RectListImpl a, RectListImpl b,
RectListImpl theUnion)
{
for (int x = MINCOORD; x < MAXCOORD; x++) {
for (int y = MINCOORD; y < MAXCOORD; y++) {
boolean inside = (a.contains(x, y) || b.contains(x, y));
if (theUnion.contains(x, y) != inside) {
error(a, b, "union failed at "+x+", "+y);
}
}
}
}
public static void testDifference(RectListImpl a, RectListImpl b) {
RectListImpl aDb = a.getDifference(b); numops++;
RectListImpl bDa = b.getDifference(a); numops++;
if (skipCheck) return;
// Note that difference is not commutative so we cannot check equals
// checkEqual(a, b, "Difference");
testDifference(a, b, aDb);
testDifference(b, a, bDa);
}
public static void testDifference(RectListImpl a, RectListImpl b,
RectListImpl theDifference)
{
for (int x = MINCOORD; x < MAXCOORD; x++) {
for (int y = MINCOORD; y < MAXCOORD; y++) {
boolean inside = (a.contains(x, y) && !b.contains(x, y));
if (theDifference.contains(x, y) != inside) {
error(a, b, "difference failed at "+x+", "+y);
}
}
}
}
public static void testIntersection(RectListImpl a, RectListImpl b) {
RectListImpl aIb = a.getIntersection(b); numops++;
RectListImpl bIa = b.getIntersection(a); numops++;
if (skipCheck) return;
checkEqual(aIb, bIa, "Intersection");
testIntersection(a, b, aIb);
testIntersection(a, b, bIa);
}
public static void testIntersection(RectListImpl a, RectListImpl b,
RectListImpl theIntersection)
{
for (int x = MINCOORD; x < MAXCOORD; x++) {
for (int y = MINCOORD; y < MAXCOORD; y++) {
boolean inside = (a.contains(x, y) && b.contains(x, y));
if (theIntersection.contains(x, y) != inside) {
error(a, b, "intersection failed at "+x+", "+y);
}
}
}
}
public static void testExclusiveOr(RectListImpl a, RectListImpl b) {
RectListImpl aXb = a.getExclusiveOr(b); numops++;
RectListImpl bXa = b.getExclusiveOr(a); numops++;
if (skipCheck) return;
checkEqual(aXb, bXa, "ExclusiveOr");
testExclusiveOr(a, b, aXb);
testExclusiveOr(a, b, bXa);
}
public static void testExclusiveOr(RectListImpl a, RectListImpl b,
RectListImpl theExclusiveOr)
{
for (int x = MINCOORD; x < MAXCOORD; x++) {
for (int y = MINCOORD; y < MAXCOORD; y++) {
boolean inside = (a.contains(x, y) != b.contains(x, y));
if (theExclusiveOr.contains(x, y) != inside) {
error(a, b, "xor failed at "+x+", "+y);
}
}
}
}
public abstract static class RectListImpl {
public static RectListImpl getInstance() {
if (useArea) {
return new AreaImpl();
} else {
return new RegionImpl();
}
}
public abstract void addRect(int lox, int loy, int hix, int hiy);
public abstract RectListImpl getTranslation(int dx, int dy);
public abstract RectListImpl getIntersection(RectListImpl rli);
public abstract RectListImpl getExclusiveOr(RectListImpl rli);
public abstract RectListImpl getDifference(RectListImpl rli);
public abstract RectListImpl getUnion(RectListImpl rli);
// Used for making sure that 3xMAX translates yields an empty region
public abstract boolean checkTransEmpty();
public abstract boolean contains(int x, int y);
public abstract int hashCode();
public abstract boolean equals(RectListImpl other);
}
public static class AreaImpl extends RectListImpl {
Area theArea;
public AreaImpl() {
}
public AreaImpl(Area a) {
theArea = a;
}
public void addRect(int lox, int loy, int hix, int hiy) {
Area a2 = new Area(new Rectangle(lox, loy, hix-lox, hiy-loy));
if (theArea == null) {
theArea = a2;
} else {
theArea.add(a2);
}
}
public RectListImpl getTranslation(int dx, int dy) {
AffineTransform at = AffineTransform.getTranslateInstance(dx, dy);
return new AreaImpl(theArea.createTransformedArea(at));
}
public RectListImpl getIntersection(RectListImpl rli) {
Area a2 = new Area(theArea);
a2.intersect(((AreaImpl) rli).theArea);
return new AreaImpl(a2);
}
public RectListImpl getExclusiveOr(RectListImpl rli) {
Area a2 = new Area(theArea);
a2.exclusiveOr(((AreaImpl) rli).theArea);
return new AreaImpl(a2);
}
public RectListImpl getDifference(RectListImpl rli) {
Area a2 = new Area(theArea);
a2.subtract(((AreaImpl) rli).theArea);
return new AreaImpl(a2);
}
public RectListImpl getUnion(RectListImpl rli) {
Area a2 = new Area(theArea);
a2.add(((AreaImpl) rli).theArea);
return new AreaImpl(a2);
}
// Used for making sure that 3xMAX translates yields an empty region
public boolean checkTransEmpty() {
// Area objects will actually survive 3 MAX translates so just
// pretend that it had the intended effect...
return true;
}
public boolean contains(int x, int y) {
return theArea.contains(x, y);
}
public int hashCode() {
// Area does not override hashCode...
return 0;
}
public boolean equals(RectListImpl other) {
return theArea.equals(((AreaImpl) other).theArea);
}
public String toString() {
return theArea.toString();
}
}
public static class RegionImpl extends RectListImpl {
Region theRegion;
public RegionImpl() {
}
public RegionImpl(Region r) {
theRegion = r;
}
public void addRect(int lox, int loy, int hix, int hiy) {
Region r2 = Region.getInstanceXYXY(lox, loy, hix, hiy);
if (theRegion == null) {
theRegion = r2;
} else {
theRegion = theRegion.getUnion(r2);
}
}
public RectListImpl getTranslation(int dx, int dy) {
return new RegionImpl(theRegion.getTranslatedRegion(dx, dy));
}
public RectListImpl getIntersection(RectListImpl rli) {
Region r2 = ((RegionImpl) rli).theRegion;
r2 = theRegion.getIntersection(r2);
return new RegionImpl(r2);
}
public RectListImpl getExclusiveOr(RectListImpl rli) {
Region r2 = ((RegionImpl) rli).theRegion;
r2 = theRegion.getExclusiveOr(r2);
return new RegionImpl(r2);
}
public RectListImpl getDifference(RectListImpl rli) {
Region r2 = ((RegionImpl) rli).theRegion;
r2 = theRegion.getDifference(r2);
return new RegionImpl(r2);
}
public RectListImpl getUnion(RectListImpl rli) {
Region r2 = ((RegionImpl) rli).theRegion;
r2 = theRegion.getUnion(r2);
return new RegionImpl(r2);
}
// Used for making sure that 3xMAX translates yields an empty region
public boolean checkTransEmpty() {
// Region objects should be empty after 3 MAX translates...
return theRegion.isEmpty();
}
public boolean contains(int x, int y) {
return theRegion.contains(x, y);
}
public int hashCode() {
return theRegion.hashCode();
}
public boolean equals(RectListImpl other) {
return theRegion.equals(((RegionImpl) other).theRegion);
}
public String toString() {
return theRegion.toString();
}
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2011, 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 7027667 7023591 7037091
*
* @summary Verifies that aa clipped rectangles are drawn, not filled.
*
* @run main Test7027667
*/
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import static java.awt.RenderingHints.*;
public class Test7027667 {
public static void main(String[] args) throws Exception {
BufferedImage bImg = new BufferedImage(512, 512, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) bImg.getGraphics();
g2d.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
g2d.setClip(new Ellipse2D.Double(0, 0, 100, 100));
g2d.drawRect(10, 10, 100, 100);
if (new Color(bImg.getRGB(50, 50)).equals(Color.white)) {
throw new Exception("Rectangle should be drawn, not filled");
}
}
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2013, 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.Graphics2D;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
/**
* @test
* @bug 8004821
* @summary Verifies that drawPolygon() works with empty arrays.
* @author Sergey Bylokhov
*/
public final class Test8004821 {
public static void main(final String[] args) {
final int[] arrEmpty = {};
final int[] arr1elem = {150};
final BufferedImage bi = new BufferedImage(300, 300,
BufferedImage.TYPE_INT_RGB);
final Graphics2D g = (Graphics2D) bi.getGraphics();
test(g, arrEmpty);
test(g, arr1elem);
g.translate(2.0, 2.0);
test(g, arrEmpty);
test(g, arr1elem);
g.scale(2.0, 2.0);
test(g, arrEmpty);
test(g, arr1elem);
g.dispose();
}
private static void test(final Graphics2D g, final int[] arr) {
g.drawPolygon(arr, arr, arr.length);
g.drawPolygon(new Polygon(arr, arr, arr.length));
g.fillPolygon(arr, arr, arr.length);
g.fillPolygon(new Polygon(arr, arr, arr.length));
g.drawPolyline(arr, arr, arr.length);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,281 @@
/*
* Copyright (c) 2007, 2019, 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
* @key headful
* @bug 6635805 6653780 6667607 8198613
* @summary Tests that the resource sharing layer API is not broken
* @author Dmitri.Trembovetski@sun.com: area=Graphics
* @modules java.desktop/sun.java2d
* java.desktop/sun.java2d.pipe
* java.desktop/sun.java2d.pipe.hw
* @compile -XDignore.symbol.file=true RSLAPITest.java
* @run main/othervm RSLAPITest
* @run main/othervm -Dsun.java2d.noddraw=true RSLAPITest
*/
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.VolatileImage;
import java.util.HashSet;
import sun.java2d.DestSurfaceProvider;
import sun.java2d.Surface;
import sun.java2d.pipe.RenderQueue;
import sun.java2d.pipe.hw.AccelGraphicsConfig;
import sun.java2d.pipe.hw.AccelSurface;
import static java.awt.Transparency.*;
import java.lang.reflect.Field;
import static sun.java2d.pipe.hw.AccelSurface.*;
import static sun.java2d.pipe.hw.ContextCapabilities.*;
public class RSLAPITest {
private static volatile boolean failed = false;
public static void main(String[] args) {
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
testGC(gc);
if (failed) {
throw new RuntimeException("Test FAILED. See err output for more");
}
System.out.println("Test PASSED.");
}
private static void testInvalidType(AccelSurface surface, int type) {
long ret = surface.getNativeResource(type);
System.out.printf(" getNativeResource(%d)=0x%x\n", type, ret);
if (ret != 0l) {
System.err.printf(
"FAILED: surface.getNativeResource(%d) returned" +
" 0x%s. It should have returned 0L\n",
type, ret);
failed = true;
}
}
private static void testD3DDeviceResourceField(final AccelSurface surface) {
try {
Class d3dc = Class.forName("sun.java2d.d3d.D3DSurfaceData");
if (d3dc.isInstance(surface)) {
Field f = d3dc.getDeclaredField("D3D_DEVICE_RESOURCE");
f.setAccessible(true);
int d3dDR = (Integer)f.get(null);
System.out.printf(
" getNativeResource(D3D_DEVICE_RESOURCE)=0x%x\n",
surface.getNativeResource(d3dDR));
}
} catch (ClassNotFoundException e) {}
catch (IllegalAccessException e) {}
catch (NoSuchFieldException e) {
System.err.println("Failed: D3DSurfaceData.D3D_DEVICE_RESOURCE" +
" field not found!");
failed = true;
}
}
private static void printSurface(Surface s) {
if (s instanceof AccelSurface) {
final AccelSurface surface = (AccelSurface) s;
System.out.println(" Accel Surface: ");
System.out.println(" type=" + surface.getType());
System.out.println(" bounds=" + surface.getBounds());
System.out.println(" nativeBounds=" + surface.getNativeBounds());
System.out.println(" isSurfaceLost=" + surface.isSurfaceLost());
System.out.println(" isValid=" + surface.isValid());
RenderQueue rq = surface.getContext().getRenderQueue();
rq.lock();
try {
rq.flushAndInvokeNow(new Runnable() {
public void run() {
System.out.printf(" getNativeResource(TEXTURE)=0x%x\n",
surface.getNativeResource(TEXTURE));
System.out.printf(" getNativeResource(RT_TEXTURE)=0x%x\n",
surface.getNativeResource(RT_TEXTURE));
System.out.printf(" getNativeResource(RT_PLAIN)=0x%x\n",
surface.getNativeResource(RT_PLAIN));
System.out.printf(
" getNativeResource(FLIP_BACKBUFFER)=0x%x\n",
surface.getNativeResource(FLIP_BACKBUFFER));
testD3DDeviceResourceField(surface);
testInvalidType(surface, -1);
testInvalidType(surface, -150);
testInvalidType(surface, 300);
testInvalidType(surface, Integer.MAX_VALUE);
testInvalidType(surface, Integer.MIN_VALUE);
}
});
} finally {
rq.unlock();
}
} else {
System.out.println("null accelerated surface");
}
}
private static void printAGC(AccelGraphicsConfig agc) {
System.out.println("Accelerated Graphics Config: " + agc);
System.out.println("Capabilities:");
System.out.printf("AGC caps: 0x%x\n",
agc.getContextCapabilities().getCaps());
System.out.println(agc.getContextCapabilities());
}
private static void testGC(GraphicsConfiguration gc) {
if (!(gc instanceof AccelGraphicsConfig)) {
System.out.println("Test passed: no hw accelerated configs found.");
return;
}
System.out.println("AccelGraphicsConfig exists, testing.");
AccelGraphicsConfig agc = (AccelGraphicsConfig) gc;
printAGC(agc);
VolatileImage vi = gc.createCompatibleVolatileImage(10, 10);
vi.validate(gc);
if (vi instanceof DestSurfaceProvider) {
System.out.println("Passed: VI is DestSurfaceProvider");
Surface s = ((DestSurfaceProvider) vi).getDestSurface();
if (s instanceof AccelSurface) {
System.out.println("Passed: Obtained Accel Surface");
printSurface((AccelSurface) s);
}
Graphics g = vi.getGraphics();
if (g instanceof DestSurfaceProvider) {
System.out.println("Passed: VI graphics is " +
"DestSurfaceProvider");
printSurface(((DestSurfaceProvider) g).getDestSurface());
}
} else {
System.out.println("VI is not DestSurfaceProvider");
}
testVICreation(agc, CAPS_RT_TEXTURE_ALPHA, TRANSLUCENT, RT_TEXTURE);
testVICreation(agc, CAPS_RT_TEXTURE_OPAQUE, OPAQUE, RT_TEXTURE);
testVICreation(agc, CAPS_RT_PLAIN_ALPHA, TRANSLUCENT, RT_PLAIN);
testVICreation(agc, agc.getContextCapabilities().getCaps(), OPAQUE,
TEXTURE);
testForNPEDuringCreation(agc);
}
private static void testVICreation(AccelGraphicsConfig agc, int cap,
int transparency, int type)
{
int caps = agc.getContextCapabilities().getCaps();
int w = 11, h = 17;
VolatileImage vi =
agc.createCompatibleVolatileImage(w, h, transparency, type);
if ((cap & caps) != 0) {
if (vi == null) {
System.out.printf("Failed: cap=%d is supported but " +
"image wasn't created\n", cap);
throw new RuntimeException("Failed: image wasn't created " +
"for supported cap");
} else {
if (!(vi instanceof DestSurfaceProvider)) {
throw new RuntimeException("Failed: created VI is not " +
"DestSurfaceProvider");
}
Surface s = ((DestSurfaceProvider) vi).getDestSurface();
if (s instanceof AccelSurface) {
AccelSurface as = (AccelSurface) s;
printSurface(as);
if (as.getType() != type) {
throw new RuntimeException("Failed: returned VI is" +
" of incorrect type: " + as.getType() +
" requested type=" + type);
} else {
System.out.printf("Passed: VI of type %d was " +
"created for cap=%d\n", type, cap);
}
if (as.getType() == TEXTURE) {
boolean ex = false;
try {
Graphics g = vi.getGraphics();
g.dispose();
} catch (UnsupportedOperationException e) {
ex = true;
}
if (!ex) {
throw new RuntimeException("Failed: " +
"texture.getGraphics() didn't throw exception");
} else {
System.out.println("Passed: VI.getGraphics()" +
" threw exception for texture-based VI");
}
}
} else {
System.out.printf("Passed: VI of type %d was " +
"created for cap=%d but accel surface is null\n",
type, cap);
}
}
} else {
if (vi != null) {
throw new RuntimeException("Failed: created VI for " +
"unsupported cap=" + cap);
}
}
}
private static void testForNPEDuringCreation(AccelGraphicsConfig agc) {
int iterations = 100;
HashSet<VolatileImage> vis = new HashSet<VolatileImage>();
GraphicsConfiguration gc = (GraphicsConfiguration)agc;
Rectangle r = gc.getBounds();
long ram = gc.getDevice().getAvailableAcceleratedMemory();
if (ram > 0) {
// guesstimate the number of iterations needed to exhaust vram
int i = 2 *
(int)(ram / (r.width * r.height * gc.getColorModel().getPixelSize()/8));
iterations = Math.max(iterations, i);
System.err.println("iterations="+iterations);
}
for (int i = 0; i < iterations; i++) {
VolatileImage vi =
agc.createCompatibleVolatileImage(r.width, r.height,
Transparency.OPAQUE,
AccelSurface.RT_PLAIN);
if (vi == null) {
break;
}
vis.add(vi);
}
for (VolatileImage vi : vis) {
vi.flush();
}
vis = null;
System.out.println("Passed: testing for possible NPEs " +
"during VI creation");
}
}

View file

@ -0,0 +1,338 @@
/*
* Copyright (c) 2007, 2018, 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 6678218 6681745 6691737 8198613
* @summary Tests that v-synced BufferStrategies works (if vsync is supported)
* @author Dmitri.Trembovetski@sun.com: area=Graphics
* @modules java.desktop/sun.java2d.pipe.hw
* @compile -XDignore.symbol.file=true VSyncedBufferStrategyTest.java
* @run main/manual/othervm VSyncedBufferStrategyTest
*/
import java.awt.AWTException;
import java.awt.BufferCapabilities;
import java.awt.BufferCapabilities.FlipContents;
import java.awt.Button;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.ImageCapabilities;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.util.concurrent.CountDownLatch;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class VSyncedBufferStrategyTest extends Canvas implements Runnable {
private static final int BLOCK_W = 50;
private static final int BLOCK_H = 200;
BufferStrategy bs;
Thread renderThread;
int blockX = 10;
int blockY = 10;
private volatile boolean done = false;
private volatile boolean requestVSync;
private boolean currentBSVSynced;
public VSyncedBufferStrategyTest(boolean requestVSync) {
this.requestVSync = requestVSync;
this.currentBSVSynced = !requestVSync;
renderThread = new Thread(this);
renderThread.start();
}
private static final BufferCapabilities defaultBC =
new BufferCapabilities(
new ImageCapabilities(true),
new ImageCapabilities(true),
null);
private void createBS(boolean requestVSync) {
if (bs != null && requestVSync == currentBSVSynced) {
return;
}
BufferCapabilities bc = defaultBC;
if (requestVSync) {
bc = new sun.java2d.pipe.hw.ExtendedBufferCapabilities(
new ImageCapabilities(true),
new ImageCapabilities(true),
FlipContents.COPIED,
sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.VSYNC_ON);
}
try {
createBufferStrategy(2, bc);
} catch (AWTException e) {
System.err.println("Warning: cap is not supported: "+bc);
e.printStackTrace();
createBufferStrategy(2);
}
currentBSVSynced = requestVSync;
bs = getBufferStrategy();
String s =
getParent() instanceof Frame ?
((Frame)getParent()).getTitle() : "parent";
System.out.println("Created BS for \"" + s + "\" frame, bs="+bs);
}
@Override
public void paint(Graphics g) {
}
@Override
public void update(Graphics g) {
}
@Override
public void run() {
while (!isShowing()) {
try { Thread.sleep(5); } catch (InterruptedException e) {}
}
try { Thread.sleep(2000); } catch (InterruptedException e) {}
try {
while (!done && isShowing()) {
createBS(requestVSync);
do {
step();
Graphics g = bs.getDrawGraphics();
render(g);
if (!bs.contentsRestored()) {
bs.show();
}
} while (bs.contentsLost());
Thread.yield();
}
} catch (Throwable e) {
// since we're not bothering with proper synchronization, exceptions
// may be thrown when the frame is closed
if (isShowing()) {
throw new RuntimeException(e);
}
}
}
int inc = 5;
private void step() {
blockX += inc;
if (blockX > getWidth() - BLOCK_W - 10) {
inc = -inc;
blockX += inc;
}
if (blockX < 10) {
inc = -inc;
blockX += inc;
}
}
private void render(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.black);
g.fillRect(blockX, blockY, BLOCK_W, BLOCK_H);
}
private void setRequestVSync(boolean reqVSync) {
requestVSync = reqVSync;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(BLOCK_W*10+20, BLOCK_H+20);
}
private static int frameNum = 0;
private static Frame createAndShowBSFrame() {
final Frame f = new Frame("Not V-Synced");
int myNum;
synchronized (VSyncedBufferStrategyTest.class) {
myNum = frameNum++;
}
final VSyncedBufferStrategyTest component =
new VSyncedBufferStrategyTest(false);
f.setIgnoreRepaint(true);
f.add("Center", component);
Panel p = new Panel();
Button b = new Button("Request VSync");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
f.setTitle("Possibly V-Synced");
component.setRequestVSync(true);
}
});
p.add(b);
b = new Button("Relinquish VSync");
b.addActionListener(new ActionListener() {
int inc = 1;
public void actionPerformed(ActionEvent e) {
f.setTitle("Not V-Synced");
component.setRequestVSync(false);
f.setSize(f.getWidth()+inc, f.getHeight());
inc = -inc;
}
});
p.add(b);
f.add("South", p);
f.pack();
f.setLocation(10, myNum * f.getHeight());
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
component.done = true;
f.dispose();
}
@Override
public void windowClosed(WindowEvent e) {
component.done = true;
}
});
return f;
}
private static final String description =
"Tests that v-synced BufferStrategy works. Note that it in some\n" +
"cases the v-sync can not be enabled, and it is accepted.\n" +
"The following however is true: only one buffer strategy at a time can\n"+
"be created v-synced. In order for other BS to become v-synced, the one\n"+
"that currently is v-synched (or its window) needs to be disposed.\n" +
"Try the following scenarios:\n" +
" - click the \"Request VSync\" button in one of the frames. If the\n"+
" behavior of the animation changes - the animation becomes smooth\n" +
" it had successfully created a v-synced BS. Note that the animation\n" +
" in other frames may also become smoother - this is a side-effect\n"+
" of one of the BS-es becoming v-synched\n" +
" - click the \"Relinquish VSync\" button on the same frame. If the\n"+
" behavior changes to the original (tearing)- it had successfully\n" +
" created a non-vsynced strategy.\n" +
" - next, try making another one v-synced. It should succeed.\n" +
" - next, try making another one v-synced - while there's already\n" +
" a v-synced frame. It should not succeed - meaning, it shouldn't\n" +
" appear to become smoother, and the behavior of the current v-synced\n" +
" frame shouldn't change.\n" +
"\n" +
"If there aren't any BufferStrategy-related exceptions or other\n" +
"issues, and the scenarios worked, the test passed, otherwise it\n"+
"failed.\n";
private static void createAndShowDescGUI(final Frame f3, final Frame f1,
final Frame f2)
throws HeadlessException, RuntimeException
{
final JFrame desc =
new JFrame("VSyncedBufferStrategyTest - Description");
desc.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
f1.dispose();
f2.dispose();
f3.dispose();
l.countDown();
}
});
JPanel p = new JPanel();
JButton bPassed = new JButton("Passed");
bPassed.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
desc.dispose();
f1.dispose();
f2.dispose();
f3.dispose();
l.countDown();
}
});
JButton bFailed = new JButton("Failed");
bFailed.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
failed = true;
desc.dispose();
f1.dispose();
f2.dispose();
f3.dispose();
l.countDown();
}
});
p.setLayout(new FlowLayout());
p.add(bPassed);
p.add(bFailed);
JTextArea ta = new JTextArea(24, 75);
ta.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
ta.setEditable(false);
ta.setText(description);
desc.add("Center", new JScrollPane(ta));
desc.add("South", p);
desc.pack();
desc.setLocation(BLOCK_W*10+50, 0);
desc.setVisible(true);
}
private static void createTestFrames() {
Frame f1 = createAndShowBSFrame();
Frame f2 = createAndShowBSFrame();
Frame f3 = createAndShowBSFrame();
createAndShowDescGUI(f1, f2, f3);
}
static boolean failed = false;
static CountDownLatch l = new CountDownLatch(1);
public static void main(String[] args) throws Exception {
EventQueue.invokeLater(new Runnable() {
public void run() {
createTestFrames();
}
});
l.await();
if (failed) {
throw new RuntimeException("Test FAILED");
}
System.out.println("Test PASSED");
}
}