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:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
392
test/jdk/java/awt/geom/HitTest/PathHitTest.java
Normal file
392
test/jdk/java/awt/geom/HitTest/PathHitTest.java
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 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.
|
||||
*/
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Canvas;
|
||||
import java.awt.Choice;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4210936 4214524
|
||||
* @summary Tests the results of the hit test methods on 3 different
|
||||
* Shape objects - Polygon, Area, and GeneralPath. Both an
|
||||
* automatic test for constraint compliance and a manual
|
||||
* test for correctness are included in this one class.
|
||||
* @library /java/awt/regtesthelpers
|
||||
* @build PassFailJFrame
|
||||
* @run main PathHitTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4210936 4214524
|
||||
* @summary Tests the results of the hit test methods on 3 different
|
||||
* Shape objects - Polygon, Area, and GeneralPath. Both an
|
||||
* automatic test for constraint compliance and a manual
|
||||
* test for correctness are included in this one class.
|
||||
* @library /java/awt/regtesthelpers
|
||||
* @build PassFailJFrame
|
||||
* @run main/manual PathHitTest manual
|
||||
*/
|
||||
|
||||
public class PathHitTest {
|
||||
|
||||
public static final int BOXSIZE = 5;
|
||||
public static final int BOXCENTER = 2;
|
||||
public static final int TESTSIZE = 400;
|
||||
public static final int NUMTESTS = (TESTSIZE + BOXSIZE - 1) / BOXSIZE;
|
||||
|
||||
public static Shape[] testShapes = new Shape[5];
|
||||
public static String[] testNames = {
|
||||
"Polygon",
|
||||
"EvenOdd GeneralPath",
|
||||
"NonZero GeneralPath",
|
||||
"Area from EO GeneralPath",
|
||||
"Area from NZ GeneralPath",
|
||||
};
|
||||
|
||||
static {
|
||||
GeneralPath gpeo = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
|
||||
Ellipse2D ell = new Ellipse2D.Float();
|
||||
Point2D center = new Point2D.Float();
|
||||
AffineTransform at = new AffineTransform();
|
||||
for (int i = 0; i < 360; i += 30) {
|
||||
center.setLocation(100, 0);
|
||||
at.setToTranslation(200, 200);
|
||||
at.rotate(i * Math.PI / 180);
|
||||
at.transform(center, center);
|
||||
ell.setFrame(center.getX() - 50, center.getY() - 50, 100, 100);
|
||||
gpeo.append(ell, false);
|
||||
}
|
||||
GeneralPath side = new GeneralPath();
|
||||
side.moveTo(0, 0);
|
||||
side.lineTo(15, 10);
|
||||
side.lineTo(30, 0);
|
||||
side.lineTo(45, -10);
|
||||
side.lineTo(60, 0);
|
||||
append4sides(gpeo, side, 20, 20);
|
||||
side.reset();
|
||||
side.moveTo(0, 0);
|
||||
side.quadTo(15, 10, 30, 0);
|
||||
side.quadTo(45, -10, 60, 0);
|
||||
append4sides(gpeo, side, 320, 20);
|
||||
side.reset();
|
||||
side.moveTo(0, 0);
|
||||
side.curveTo(15, 10, 45, -10, 60, 0);
|
||||
append4sides(gpeo, side, 20, 320);
|
||||
|
||||
GeneralPath gpnz = new GeneralPath(GeneralPath.WIND_NON_ZERO);
|
||||
gpnz.append(gpeo, false);
|
||||
Polygon p = new Polygon();
|
||||
p.addPoint( 50, 50);
|
||||
p.addPoint( 60, 350);
|
||||
p.addPoint(250, 340);
|
||||
p.addPoint(260, 150);
|
||||
p.addPoint(140, 140);
|
||||
p.addPoint(150, 260);
|
||||
p.addPoint(340, 250);
|
||||
p.addPoint(350, 60);
|
||||
testShapes[0] = p;
|
||||
testShapes[1] = gpeo;
|
||||
testShapes[2] = gpnz;
|
||||
testShapes[3] = new Area(gpeo);
|
||||
testShapes[3].getPathIterator(null);
|
||||
testShapes[4] = new Area(gpnz);
|
||||
testShapes[4].getPathIterator(null);
|
||||
}
|
||||
|
||||
private static void append4sides(GeneralPath path, GeneralPath side,
|
||||
double xoff, double yoff) {
|
||||
AffineTransform at = new AffineTransform();
|
||||
at.setToTranslation(xoff, yoff);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
path.append(side.getPathIterator(at), i != 0);
|
||||
at.rotate(Math.toRadians(90), 30, 30);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] argv) throws Exception {
|
||||
if (argv.length > 0 && argv[0].equals("manual")) {
|
||||
PathHitTestManual.doManual();
|
||||
} else {
|
||||
int totalerrs = 0;
|
||||
for (int i = 0; i < testShapes.length; i++) {
|
||||
totalerrs += testshape(testShapes[i], testNames[i]);
|
||||
}
|
||||
if (totalerrs != 0) {
|
||||
throw new RuntimeException(totalerrs +
|
||||
" constraint conditions violated!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int testshape(Shape s, String name) {
|
||||
int numerrs = 0;
|
||||
long start = System.currentTimeMillis();
|
||||
for (int y = 0; y < TESTSIZE; y += BOXSIZE) {
|
||||
for (int x = 0; x < TESTSIZE; x += BOXSIZE) {
|
||||
boolean rectintersects = s.intersects(x, y, BOXSIZE, BOXSIZE);
|
||||
boolean rectcontains = s.contains(x, y, BOXSIZE, BOXSIZE);
|
||||
boolean pointcontains = s.contains(x + BOXCENTER, y + BOXCENTER);
|
||||
if (rectcontains && !rectintersects) {
|
||||
System.err.println("rect is contained " +
|
||||
"but does not intersect!");
|
||||
numerrs++;
|
||||
}
|
||||
if (rectcontains && !pointcontains) {
|
||||
System.err.println("rect is contained " +
|
||||
"but center is not contained!");
|
||||
numerrs++;
|
||||
}
|
||||
if (pointcontains && !rectintersects) {
|
||||
System.err.println("center is contained " +
|
||||
"but rect does not intersect!");
|
||||
numerrs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
System.out.println(name + " completed in " +
|
||||
(end - start) + "ms with " +
|
||||
numerrs + " errors");
|
||||
return numerrs;
|
||||
}
|
||||
|
||||
static class PathHitTestManual extends Panel {
|
||||
private static final String INSTRUCTIONS = """
|
||||
This test displays the results of hit testing 5 different Shape
|
||||
objects one at a time.
|
||||
|
||||
You can switch between shapes using the Choice component located
|
||||
at the bottom of the window.
|
||||
|
||||
Each square in the test represents the
|
||||
return values of the hit testing operators for that square region:
|
||||
|
||||
yellow - not yet tested
|
||||
translucent blue overlay - the shape being tested
|
||||
|
||||
black - all outside
|
||||
dark gray - rectangle intersects shape
|
||||
light gray - rectangle intersects and center point is inside shape
|
||||
white - rectangle is entirely contained in shape
|
||||
red - some constraint was violated, including:
|
||||
rectangle is contained, but center point is not
|
||||
rectangle is contained, but rectangle.intersects is false
|
||||
centerpoint is contained, but rectangle.intersects is false
|
||||
|
||||
Visually inspect the results to see if they match the above table.
|
||||
Note that it is not a violation for rectangles that are entirely
|
||||
inside the path to be light gray instead of white since sometimes
|
||||
the path is complex enough to make an exact determination expensive.
|
||||
You might see this on the GeneralPath NonZero example where the
|
||||
circles that make up the path cross over the interior of the shape
|
||||
and cause the hit testing methods to guess that the rectangle is
|
||||
not guaranteed to be contained within the shape.
|
||||
""";
|
||||
|
||||
PathHitTestCanvas phtc;
|
||||
|
||||
public void init() {
|
||||
setLayout(new BorderLayout());
|
||||
phtc = new PathHitTestCanvas();
|
||||
add("Center", phtc);
|
||||
final Choice ch = new Choice();
|
||||
for (int i = 0; i < PathHitTest.testNames.length; i++) {
|
||||
ch.add(PathHitTest.testNames[i]);
|
||||
}
|
||||
ch.addItemListener(e -> phtc.setShape(ch.getSelectedIndex()));
|
||||
ch.select(0);
|
||||
phtc.setShape(0);
|
||||
add("South", ch);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
phtc.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
phtc.stop();
|
||||
}
|
||||
|
||||
public static class PathHitTestCanvas extends Canvas implements Runnable {
|
||||
public static final Color[] colors = {
|
||||
/* contains? point in? intersects? */
|
||||
Color.black, /* NO NO NO */
|
||||
Color.darkGray, /* NO NO YES */
|
||||
Color.red, /* NO YES NO */
|
||||
Color.lightGray, /* NO YES YES */
|
||||
Color.red, /* YES NO NO */
|
||||
Color.red, /* YES NO YES */
|
||||
Color.red, /* YES YES NO */
|
||||
Color.white, /* YES YES YES */
|
||||
Color.yellow, /* used for untested points */
|
||||
};
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(TESTSIZE, TESTSIZE);
|
||||
}
|
||||
|
||||
public synchronized void start() {
|
||||
if (!testdone) {
|
||||
renderer = new Thread(this);
|
||||
renderer.setPriority(Thread.MIN_PRIORITY);
|
||||
renderer.start();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
renderer = null;
|
||||
}
|
||||
|
||||
private Thread renderer;
|
||||
private int shapeIndex = 0;
|
||||
private byte[] indices = new byte[NUMTESTS * NUMTESTS];
|
||||
boolean testdone = false;
|
||||
|
||||
private synchronized void setShape(int index) {
|
||||
shapeIndex = index;
|
||||
testdone = false;
|
||||
start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Thread me = Thread.currentThread();
|
||||
Graphics2D g2d = (Graphics2D) getGraphics();
|
||||
byte[] indices;
|
||||
Shape s = testShapes[shapeIndex];
|
||||
synchronized (this) {
|
||||
if (renderer != me) {
|
||||
return;
|
||||
}
|
||||
this.indices = new byte[NUMTESTS * NUMTESTS];
|
||||
java.util.Arrays.fill(this.indices, (byte) 8);
|
||||
indices = this.indices;
|
||||
}
|
||||
|
||||
System.err.printf("%s %s\n", g2d, Color.yellow);
|
||||
g2d.setColor(Color.yellow);
|
||||
g2d.fillRect(0, 0, TESTSIZE, TESTSIZE);
|
||||
int numtests = 0;
|
||||
long start = System.currentTimeMillis();
|
||||
for (int y = 0; renderer == me && y < TESTSIZE; y += BOXSIZE) {
|
||||
for (int x = 0; renderer == me && x < TESTSIZE; x += BOXSIZE) {
|
||||
byte index = 0;
|
||||
if (s.intersects(x, y, BOXSIZE, BOXSIZE)) {
|
||||
index += 1;
|
||||
}
|
||||
if (s.contains(x + BOXCENTER, y + BOXCENTER)) {
|
||||
index += 2;
|
||||
}
|
||||
if (s.contains(x, y, BOXSIZE, BOXSIZE)) {
|
||||
index += 4;
|
||||
}
|
||||
numtests++;
|
||||
int i = (y / BOXSIZE) * NUMTESTS + (x / BOXSIZE);
|
||||
indices[i] = index;
|
||||
g2d.setColor(colors[index]);
|
||||
g2d.fillRect(x, y, BOXSIZE, BOXSIZE);
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
if (renderer != me) {
|
||||
return;
|
||||
}
|
||||
g2d.setColor(new Color(0, 0, 1, .2f));
|
||||
g2d.fill(s);
|
||||
testdone = true;
|
||||
long end = System.currentTimeMillis();
|
||||
System.out.println(numtests + " tests took " + (end - start) + "ms");
|
||||
}
|
||||
}
|
||||
|
||||
public void paint(Graphics g) {
|
||||
g.setColor(Color.yellow);
|
||||
g.fillRect(0, 0, TESTSIZE, TESTSIZE);
|
||||
byte[] indices = this.indices;
|
||||
if (indices != null) {
|
||||
for (int y = 0; y < TESTSIZE; y += BOXSIZE) {
|
||||
for (int x = 0; x < TESTSIZE; x += BOXSIZE) {
|
||||
int i = (y / BOXSIZE) * NUMTESTS + (x / BOXSIZE);
|
||||
g.setColor(colors[indices[i]]);
|
||||
g.fillRect(x, y, BOXSIZE, BOXSIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
g2d.setColor(new Color(0, 0, 1, .2f));
|
||||
g2d.fill(testShapes[shapeIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
static volatile PathHitTestManual pathHitTestManual;
|
||||
|
||||
private static void createAndShowGUI() {
|
||||
pathHitTestManual = new PathHitTestManual();
|
||||
Frame frame = new Frame("PathHitTestManual test window");
|
||||
|
||||
frame.add(pathHitTestManual);
|
||||
frame.setSize(400, 450);
|
||||
|
||||
PassFailJFrame.addTestWindow(frame);
|
||||
PassFailJFrame.positionTestWindow(frame, PassFailJFrame.Position.HORIZONTAL);
|
||||
|
||||
frame.setVisible(true);
|
||||
|
||||
pathHitTestManual.init();
|
||||
pathHitTestManual.start();
|
||||
}
|
||||
|
||||
public static void doManual() throws Exception {
|
||||
PassFailJFrame passFailJFrame = PassFailJFrame.builder()
|
||||
.title("PathHitTestManual Instructions")
|
||||
.instructions(INSTRUCTIONS)
|
||||
.testTimeOut(5)
|
||||
.rows(30)
|
||||
.columns(70)
|
||||
.screenCapture()
|
||||
.build();
|
||||
|
||||
EventQueue.invokeAndWait(PathHitTestManual::createAndShowGUI);
|
||||
try {
|
||||
passFailJFrame.awaitAndCheck();
|
||||
} finally {
|
||||
pathHitTestManual.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue