3789983e89
Reviewed-by: darcy, ihse
1635 lines
55 KiB
Java
1635 lines
55 KiB
Java
/*
|
|
* Copyright (c) 2008, 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 6766342
|
|
* @summary Tests clipping invariance for AA rectangle and line primitives
|
|
* @run main RenderClipTest -strict -readfile 6766342.tests
|
|
* @run main RenderClipTest -rectsuite -count 10
|
|
*/
|
|
|
|
import java.awt.*;
|
|
import java.awt.geom.*;
|
|
import java.awt.image.*;
|
|
import java.awt.event.*;
|
|
import java.util.Vector;
|
|
import java.io.*;
|
|
|
|
public class RenderClipTest {
|
|
public static double randDblCoord() {
|
|
return Math.random()*60 - 10;
|
|
}
|
|
|
|
public static float randFltCoord() {
|
|
return (float) randDblCoord();
|
|
}
|
|
|
|
public static int randIntCoord() {
|
|
return (int) Math.round(randDblCoord());
|
|
}
|
|
|
|
public static int randInt(int n) {
|
|
return ((int) (Math.random() * (n*4))) >> 2;
|
|
}
|
|
|
|
static int numtests;
|
|
static int numerrors;
|
|
static int numfillfailures;
|
|
static int numstrokefailures;
|
|
static int maxerr;
|
|
|
|
static boolean useAA;
|
|
static boolean strokePure;
|
|
static boolean testFill;
|
|
static boolean testDraw;
|
|
static boolean silent;
|
|
static boolean verbose;
|
|
static boolean strict;
|
|
static boolean showErrors;
|
|
static float lw;
|
|
static double rot;
|
|
|
|
static BufferedImage imgref;
|
|
static BufferedImage imgtst;
|
|
|
|
static Graphics2D grefclear;
|
|
static Graphics2D gtstclear;
|
|
static Graphics2D grefrender;
|
|
static Graphics2D gtstrender;
|
|
|
|
public static abstract class AnnotatedRenderOp {
|
|
public static AnnotatedRenderOp parse(String str) {
|
|
AnnotatedRenderOp ar;
|
|
if (((ar = Cubic.tryparse(str)) != null) ||
|
|
((ar = Quad.tryparse(str)) != null) ||
|
|
((ar = Poly.tryparse(str)) != null) ||
|
|
((ar = Path.tryparse(str)) != null) ||
|
|
((ar = Rect.tryparse(str)) != null) ||
|
|
((ar = Line.tryparse(str)) != null) ||
|
|
((ar = RectMethod.tryparse(str)) != null) ||
|
|
((ar = LineMethod.tryparse(str)) != null))
|
|
{
|
|
return ar;
|
|
}
|
|
System.err.println("Unable to parse shape: "+str);
|
|
return null;
|
|
}
|
|
|
|
public abstract void randomize();
|
|
|
|
public abstract void fill(Graphics2D g2d);
|
|
|
|
public abstract void draw(Graphics2D g2d);
|
|
}
|
|
|
|
public static abstract class AnnotatedShapeOp extends AnnotatedRenderOp {
|
|
public abstract Shape getShape();
|
|
|
|
public void fill(Graphics2D g2d) {
|
|
g2d.fill(getShape());
|
|
}
|
|
|
|
public void draw(Graphics2D g2d) {
|
|
g2d.draw(getShape());
|
|
}
|
|
}
|
|
|
|
public static void usage(String err) {
|
|
if (err != null) {
|
|
System.err.println(err);
|
|
}
|
|
System.err.println("usage: java RenderClipTest "+
|
|
"[-read[file F]] [-rectsuite] [-fill] [-draw]");
|
|
System.err.println(" "+
|
|
"[-aa] [-pure] [-lw N] [-rot N]");
|
|
System.err.println(" "+
|
|
"[-rectmethod] [-linemethod] [-rect] [-line]");
|
|
System.err.println(" "+
|
|
"[-cubic] [-quad] [-poly] [-path]");
|
|
System.err.println(" "+
|
|
"[-silent] [-verbose] [-showerr] [-count N]");
|
|
System.err.println(" "+
|
|
"[-strict] [-usage]");
|
|
System.err.println(" -read Read test data from stdin");
|
|
System.err.println(" -readfile F Read test data from file F");
|
|
System.err.println(" -rectsuite Run a suite of rect/line tests");
|
|
System.err.println(" -fill Test g.fill*(...)");
|
|
System.err.println(" -draw Test g.draw*(...)");
|
|
System.err.println(" -aa Use antialiased rendering");
|
|
System.err.println(" -pure Use STROKE_PURE hint");
|
|
System.err.println(" -lw N Test line widths of N "+
|
|
"(default 1.0)");
|
|
System.err.println(" -rot N Test rotation by N degrees "+
|
|
"(default 0.0)");
|
|
System.err.println(" -rectmethod Test fillRect/drawRect methods");
|
|
System.err.println(" -linemethod Test drawLine method");
|
|
System.err.println(" -rect Test Rectangle2D shapes");
|
|
System.err.println(" -line Test Line2D shapes");
|
|
System.err.println(" -cubic Test CubicCurve2D shapes");
|
|
System.err.println(" -quad Test QuadCurve2D shapes");
|
|
System.err.println(" -poly Test Polygon shapes");
|
|
System.err.println(" -path Test GeneralPath shapes");
|
|
System.err.println(" -silent Do not print out error curves");
|
|
System.err.println(" -verbose Print out progress info");
|
|
System.err.println(" -showerr Display errors on screen");
|
|
System.err.println(" -count N N tests per shape, then exit "+
|
|
"(default 1000)");
|
|
System.err.println(" -strict All failures are important");
|
|
System.err.println(" -usage Print this help, then exit");
|
|
System.exit((err != null) ? -1 : 0);
|
|
}
|
|
|
|
public static void main(String argv[]) {
|
|
boolean readTests = false;
|
|
String readFile = null;
|
|
boolean rectsuite = false;
|
|
int count = 1000;
|
|
lw = 1.0f;
|
|
rot = 0.0;
|
|
Vector<AnnotatedRenderOp> testOps = new Vector<AnnotatedRenderOp>();
|
|
for (int i = 0; i < argv.length; i++) {
|
|
String arg = argv[i].toLowerCase();
|
|
if (arg.equals("-aa")) {
|
|
useAA = true;
|
|
} else if (arg.equals("-pure")) {
|
|
strokePure = true;
|
|
} else if (arg.equals("-fill")) {
|
|
testFill = true;
|
|
} else if (arg.equals("-draw")) {
|
|
testDraw = true;
|
|
} else if (arg.equals("-lw")) {
|
|
if (i+1 >= argv.length) {
|
|
usage("Missing argument: "+argv[i]);
|
|
}
|
|
lw = Float.parseFloat(argv[++i]);
|
|
} else if (arg.equals("-rot")) {
|
|
if (i+1 >= argv.length) {
|
|
usage("Missing argument: "+argv[i]);
|
|
}
|
|
rot = Double.parseDouble(argv[++i]);
|
|
} else if (arg.equals("-cubic")) {
|
|
testOps.add(new Cubic());
|
|
} else if (arg.equals("-quad")) {
|
|
testOps.add(new Quad());
|
|
} else if (arg.equals("-poly")) {
|
|
testOps.add(new Poly());
|
|
} else if (arg.equals("-path")) {
|
|
testOps.add(new Path());
|
|
} else if (arg.equals("-rect")) {
|
|
testOps.add(new Rect());
|
|
} else if (arg.equals("-line")) {
|
|
testOps.add(new Line());
|
|
} else if (arg.equals("-rectmethod")) {
|
|
testOps.add(new RectMethod());
|
|
} else if (arg.equals("-linemethod")) {
|
|
testOps.add(new LineMethod());
|
|
} else if (arg.equals("-verbose")) {
|
|
verbose = true;
|
|
} else if (arg.equals("-strict")) {
|
|
strict = true;
|
|
} else if (arg.equals("-silent")) {
|
|
silent = true;
|
|
} else if (arg.equals("-showerr")) {
|
|
showErrors = true;
|
|
} else if (arg.equals("-readfile")) {
|
|
if (i+1 >= argv.length) {
|
|
usage("Missing argument: "+argv[i]);
|
|
}
|
|
readTests = true;
|
|
readFile = argv[++i];
|
|
} else if (arg.equals("-read")) {
|
|
readTests = true;
|
|
readFile = null;
|
|
} else if (arg.equals("-rectsuite")) {
|
|
rectsuite = true;
|
|
} else if (arg.equals("-count")) {
|
|
if (i+1 >= argv.length) {
|
|
usage("Missing argument: "+argv[i]);
|
|
}
|
|
count = Integer.parseInt(argv[++i]);
|
|
} else if (arg.equals("-usage")) {
|
|
usage(null);
|
|
} else {
|
|
usage("Unknown argument: "+argv[i]);
|
|
}
|
|
}
|
|
if (readTests) {
|
|
if (rectsuite || testDraw || testFill ||
|
|
useAA || strokePure ||
|
|
lw != 1.0f || rot != 0.0 ||
|
|
testOps.size() > 0)
|
|
{
|
|
usage("Should not specify test types with -read options");
|
|
}
|
|
} else if (rectsuite) {
|
|
if (testDraw || testFill ||
|
|
useAA || strokePure ||
|
|
lw != 1.0f || rot != 0.0 ||
|
|
testOps.size() > 0)
|
|
{
|
|
usage("Should not specify test types with -rectsuite option");
|
|
}
|
|
} else {
|
|
if (!testDraw && !testFill) {
|
|
usage("No work: Must specify one or both of "+
|
|
"-fill or -draw");
|
|
}
|
|
if (testOps.size() == 0) {
|
|
usage("No work: Must specify one or more of "+
|
|
"-rect[method], -line[method], "+
|
|
"-cubic, -quad, -poly, or -path");
|
|
}
|
|
}
|
|
initImages();
|
|
if (readTests) {
|
|
try {
|
|
InputStream is;
|
|
if (readFile == null) {
|
|
is = System.in;
|
|
} else {
|
|
File f =
|
|
new File(System.getProperty("test.src", "."),
|
|
readFile);
|
|
is = new FileInputStream(f);
|
|
}
|
|
parseAndRun(is);
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
} else if (rectsuite) {
|
|
runRectSuite(count);
|
|
} else {
|
|
initGCs();
|
|
for (int k = 0; k < testOps.size(); k++) {
|
|
AnnotatedRenderOp ar = testOps.get(k);
|
|
runRandomTests(ar, count);
|
|
}
|
|
disposeGCs();
|
|
}
|
|
grefclear.dispose();
|
|
gtstclear.dispose();
|
|
grefclear = gtstclear = null;
|
|
reportStatistics();
|
|
}
|
|
|
|
public static int reportStatistics() {
|
|
String connector = "";
|
|
if (numfillfailures > 0) {
|
|
System.out.print(numfillfailures+" fills ");
|
|
connector = "and ";
|
|
}
|
|
if (numstrokefailures > 0) {
|
|
System.out.print(connector+numstrokefailures+" strokes ");
|
|
}
|
|
int totalfailures = numfillfailures + numstrokefailures;
|
|
if (totalfailures == 0) {
|
|
System.out.print("0 ");
|
|
}
|
|
System.out.println("out of "+numtests+" tests failed...");
|
|
int critical = numerrors;
|
|
if (strict) {
|
|
critical += totalfailures;
|
|
}
|
|
if (critical > 0) {
|
|
throw new RuntimeException(critical+" tests had critical errors");
|
|
}
|
|
System.out.println("No tests had critical errors");
|
|
return (numerrors+totalfailures);
|
|
}
|
|
|
|
public static void runRectSuite(int count) {
|
|
AnnotatedRenderOp ops[] = {
|
|
new Rect(),
|
|
new RectMethod(),
|
|
new Line(),
|
|
new LineMethod(),
|
|
};
|
|
// Sometimes different fill algorithms are chosen for
|
|
// thin and wide line modes, make sure we test both...
|
|
float filllinewidths[] = { 0.0f, 2.0f };
|
|
float drawlinewidths[] = { 0.0f, 0.5f, 1.0f,
|
|
2.0f, 2.5f,
|
|
5.0f, 5.3f };
|
|
double rotations[] = { 0.0, 15.0, 90.0,
|
|
135.0, 180.0,
|
|
200.0, 270.0,
|
|
300.0};
|
|
for (AnnotatedRenderOp ar: ops) {
|
|
for (double r: rotations) {
|
|
rot = r;
|
|
for (int i = 0; i < 8; i++) {
|
|
float linewidths[];
|
|
if ((i & 1) == 0) {
|
|
if ((ar instanceof Line) ||
|
|
(ar instanceof LineMethod))
|
|
{
|
|
continue;
|
|
}
|
|
testFill = true;
|
|
testDraw = false;
|
|
linewidths = filllinewidths;
|
|
} else {
|
|
testFill = false;
|
|
testDraw = true;
|
|
linewidths = drawlinewidths;
|
|
}
|
|
useAA = ((i & 2) != 0);
|
|
strokePure = ((i & 4) != 0);
|
|
for (float w : linewidths) {
|
|
lw = w;
|
|
runSuiteTests(ar, count);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void runSuiteTests(AnnotatedRenderOp ar, int count) {
|
|
if (verbose) {
|
|
System.out.print("Running ");
|
|
System.out.print(testFill ? "Fill " : "Draw ");
|
|
System.out.print(BaseName(ar));
|
|
if (useAA) {
|
|
System.out.print(" AA");
|
|
}
|
|
if (strokePure) {
|
|
System.out.print(" Pure");
|
|
}
|
|
if (lw != 1.0f) {
|
|
System.out.print(" lw="+lw);
|
|
}
|
|
if (rot != 0.0f) {
|
|
System.out.print(" rot="+rot);
|
|
}
|
|
System.out.println();
|
|
}
|
|
initGCs();
|
|
runRandomTests(ar, count);
|
|
disposeGCs();
|
|
}
|
|
|
|
public static String BaseName(AnnotatedRenderOp ar) {
|
|
String s = ar.toString();
|
|
int leftparen = s.indexOf('(');
|
|
if (leftparen >= 0) {
|
|
s = s.substring(0, leftparen);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
public static void runRandomTests(AnnotatedRenderOp ar, int count) {
|
|
for (int i = 0; i < count; i++) {
|
|
ar.randomize();
|
|
if (testDraw) {
|
|
test(ar, false);
|
|
}
|
|
if (testFill) {
|
|
test(ar, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void initImages() {
|
|
imgref = new BufferedImage(40, 40, BufferedImage.TYPE_INT_RGB);
|
|
imgtst = new BufferedImage(40, 40, BufferedImage.TYPE_INT_RGB);
|
|
grefclear = imgref.createGraphics();
|
|
gtstclear = imgtst.createGraphics();
|
|
grefclear.setColor(Color.white);
|
|
gtstclear.setColor(Color.white);
|
|
}
|
|
|
|
public static void initGCs() {
|
|
grefrender = imgref.createGraphics();
|
|
gtstrender = imgtst.createGraphics();
|
|
gtstrender.clipRect(10, 10, 20, 20);
|
|
grefrender.setColor(Color.blue);
|
|
gtstrender.setColor(Color.blue);
|
|
if (lw != 1.0f) {
|
|
BasicStroke bs = new BasicStroke(lw);
|
|
grefrender.setStroke(bs);
|
|
gtstrender.setStroke(bs);
|
|
}
|
|
if (rot != 0.0) {
|
|
double rotrad = Math.toRadians(rot);
|
|
grefrender.rotate(rotrad, 20, 20);
|
|
gtstrender.rotate(rotrad, 20, 20);
|
|
}
|
|
if (strokePure) {
|
|
grefrender.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
|
|
RenderingHints.VALUE_STROKE_PURE);
|
|
gtstrender.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
|
|
RenderingHints.VALUE_STROKE_PURE);
|
|
}
|
|
if (useAA) {
|
|
grefrender.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
|
RenderingHints.VALUE_ANTIALIAS_ON);
|
|
gtstrender.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
|
RenderingHints.VALUE_ANTIALIAS_ON);
|
|
maxerr = 1;
|
|
}
|
|
}
|
|
|
|
public static void disposeGCs() {
|
|
grefrender.dispose();
|
|
gtstrender.dispose();
|
|
grefrender = gtstrender = null;
|
|
}
|
|
|
|
public static void parseAndRun(InputStream in) throws IOException {
|
|
BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
|
String str;
|
|
while ((str = br.readLine()) != null) {
|
|
if (str.startsWith("Stroked ") || str.startsWith("Filled ")) {
|
|
parseTest(str);
|
|
continue;
|
|
}
|
|
if (str.startsWith("Running ")) {
|
|
continue;
|
|
}
|
|
if (str.startsWith("Failed: ")) {
|
|
continue;
|
|
}
|
|
if (str.indexOf(" out of ") > 0 &&
|
|
str.indexOf(" tests failed...") > 0)
|
|
{
|
|
continue;
|
|
}
|
|
if (str.indexOf(" tests had critical errors") > 0) {
|
|
continue;
|
|
}
|
|
System.err.println("Unparseable line: "+str);
|
|
}
|
|
}
|
|
|
|
public static void parseTest(String origstr) {
|
|
String str = origstr;
|
|
boolean isfill = false;
|
|
useAA = strokePure = false;
|
|
lw = 1.0f;
|
|
rot = 0.0;
|
|
if (str.startsWith("Stroked ")) {
|
|
str = str.substring(8);
|
|
isfill = false;
|
|
} else if (str.startsWith("Filled ")) {
|
|
str = str.substring(7);
|
|
isfill = true;
|
|
} else {
|
|
System.err.println("Unparseable test line: "+origstr);
|
|
}
|
|
if (str.startsWith("AA ")) {
|
|
str = str.substring(3);
|
|
useAA = true;
|
|
}
|
|
if (str.startsWith("Pure ")) {
|
|
str = str.substring(5);
|
|
strokePure = true;
|
|
}
|
|
if (str.startsWith("Lw=")) {
|
|
int index = str.indexOf(' ', 3);
|
|
if (index > 0) {
|
|
lw = Float.parseFloat(str.substring(3, index));
|
|
str = str.substring(index+1);
|
|
}
|
|
}
|
|
if (str.startsWith("Rot=")) {
|
|
int index = str.indexOf(' ', 4);
|
|
if (index > 0) {
|
|
rot = Double.parseDouble(str.substring(4, index));
|
|
str = str.substring(index+1);
|
|
}
|
|
}
|
|
AnnotatedRenderOp ar = AnnotatedRenderOp.parse(str);
|
|
if (ar != null) {
|
|
initGCs();
|
|
test(ar, isfill);
|
|
disposeGCs();
|
|
} else {
|
|
System.err.println("Unparseable test line: "+origstr);
|
|
}
|
|
}
|
|
|
|
public static void test(AnnotatedRenderOp ar, boolean isfill) {
|
|
grefclear.fillRect(0, 0, 40, 40);
|
|
gtstclear.fillRect(0, 0, 40, 40);
|
|
if (isfill) {
|
|
ar.fill(grefrender);
|
|
ar.fill(gtstrender);
|
|
} else {
|
|
ar.draw(grefrender);
|
|
ar.draw(gtstrender);
|
|
}
|
|
check(imgref, imgtst, ar, isfill);
|
|
}
|
|
|
|
public static int[] getData(BufferedImage img) {
|
|
Raster r = img.getRaster();
|
|
DataBufferInt dbi = (DataBufferInt) r.getDataBuffer();
|
|
return dbi.getData();
|
|
}
|
|
|
|
public static int getScan(BufferedImage img) {
|
|
Raster r = img.getRaster();
|
|
SinglePixelPackedSampleModel sppsm =
|
|
(SinglePixelPackedSampleModel) r.getSampleModel();
|
|
return sppsm.getScanlineStride();
|
|
}
|
|
|
|
public static int getOffset(BufferedImage img) {
|
|
Raster r = img.getRaster();
|
|
SinglePixelPackedSampleModel sppsm =
|
|
(SinglePixelPackedSampleModel) r.getSampleModel();
|
|
return sppsm.getOffset(-r.getSampleModelTranslateX(),
|
|
-r.getSampleModelTranslateY());
|
|
}
|
|
|
|
final static int opaque = 0xff000000;
|
|
final static int whitergb = Color.white.getRGB();
|
|
|
|
public static final int maxdiff(int rgb1, int rgb2) {
|
|
int maxd = 0;
|
|
for (int i = 0; i < 32; i += 8) {
|
|
int c1 = (rgb1 >> i) & 0xff;
|
|
int c2 = (rgb2 >> i) & 0xff;
|
|
int d = Math.abs(c1-c2);
|
|
if (maxd < d) {
|
|
maxd = d;
|
|
}
|
|
}
|
|
return maxd;
|
|
}
|
|
|
|
public static void check(BufferedImage imgref, BufferedImage imgtst,
|
|
AnnotatedRenderOp ar, boolean wasfill)
|
|
{
|
|
numtests++;
|
|
int dataref[] = getData(imgref);
|
|
int datatst[] = getData(imgtst);
|
|
int scanref = getScan(imgref);
|
|
int scantst = getScan(imgtst);
|
|
int offref = getOffset(imgref);
|
|
int offtst = getOffset(imgtst);
|
|
|
|
// We want to check for errors outside the clip at a higher
|
|
// priority than errors involving different pixels touched
|
|
// inside the clip.
|
|
|
|
// Check above clip
|
|
if (check(ar, wasfill,
|
|
null, 0, 0,
|
|
datatst, scantst, offtst,
|
|
0, 0, 40, 10))
|
|
{
|
|
return;
|
|
}
|
|
// Check below clip
|
|
if (check(ar, wasfill,
|
|
null, 0, 0,
|
|
datatst, scantst, offtst,
|
|
0, 30, 40, 40))
|
|
{
|
|
return;
|
|
}
|
|
// Check left of clip
|
|
if (check(ar, wasfill,
|
|
null, 0, 0,
|
|
datatst, scantst, offtst,
|
|
0, 10, 10, 30))
|
|
{
|
|
return;
|
|
}
|
|
// Check right of clip
|
|
if (check(ar, wasfill,
|
|
null, 0, 0,
|
|
datatst, scantst, offtst,
|
|
30, 10, 40, 30))
|
|
{
|
|
return;
|
|
}
|
|
// Check inside clip
|
|
check(ar, wasfill,
|
|
dataref, scanref, offref,
|
|
datatst, scantst, offtst,
|
|
10, 10, 30, 30);
|
|
}
|
|
|
|
public static boolean check(AnnotatedRenderOp ar, boolean wasfill,
|
|
int dataref[], int scanref, int offref,
|
|
int datatst[], int scantst, int offtst,
|
|
int x0, int y0, int x1, int y1)
|
|
{
|
|
offref += scanref * y0;
|
|
offtst += scantst * y0;
|
|
for (int y = y0; y < y1; y++) {
|
|
for (int x = x0; x < x1; x++) {
|
|
boolean failed;
|
|
String reason;
|
|
int rgbref;
|
|
int rgbtst;
|
|
|
|
rgbtst = datatst[offtst+x] | opaque;
|
|
if (dataref == null) {
|
|
/* Outside of clip, must be white, no error tolerance */
|
|
rgbref = whitergb;
|
|
failed = (rgbtst != rgbref);
|
|
reason = "stray pixel rendered outside of clip";
|
|
} else {
|
|
/* Inside of clip, check for maxerr delta in components */
|
|
rgbref = dataref[offref+x] | opaque;
|
|
failed = (rgbref != rgbtst &&
|
|
maxdiff(rgbref, rgbtst) > maxerr);
|
|
reason = "different pixel rendered inside clip";
|
|
}
|
|
if (failed) {
|
|
if (dataref == null) {
|
|
numerrors++;
|
|
}
|
|
if (wasfill) {
|
|
numfillfailures++;
|
|
} else {
|
|
numstrokefailures++;
|
|
}
|
|
if (!silent) {
|
|
System.out.println("Failed: "+reason+" at "+x+", "+y+
|
|
" ["+Integer.toHexString(rgbref)+
|
|
" != "+Integer.toHexString(rgbtst)+
|
|
"]");
|
|
System.out.print(wasfill ? "Filled " : "Stroked ");
|
|
if (useAA) System.out.print("AA ");
|
|
if (strokePure) System.out.print("Pure ");
|
|
if (lw != 1) System.out.print("Lw="+lw+" ");
|
|
if (rot != 0) System.out.print("Rot="+rot+" ");
|
|
System.out.println(ar);
|
|
}
|
|
if (showErrors) {
|
|
show(imgref, imgtst);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
offref += scanref;
|
|
offtst += scantst;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static ErrorWindow errw;
|
|
|
|
public static void show(BufferedImage imgref, BufferedImage imgtst) {
|
|
ErrorWindow errw = new ErrorWindow();
|
|
errw.setImages(imgref, imgtst);
|
|
errw.setVisible(true);
|
|
errw.waitForHide();
|
|
errw.dispose();
|
|
}
|
|
|
|
public static class Cubic extends AnnotatedShapeOp {
|
|
public static Cubic tryparse(String str) {
|
|
str = str.trim();
|
|
if (!str.startsWith("Cubic(")) {
|
|
return null;
|
|
}
|
|
str = str.substring(6);
|
|
double coords[] = new double[8];
|
|
boolean foundparen = false;
|
|
for (int i = 0; i < coords.length; i++) {
|
|
int index = str.indexOf(",");
|
|
if (index < 0) {
|
|
if (i < coords.length-1) {
|
|
return null;
|
|
}
|
|
index = str.indexOf(")");
|
|
if (index < 0) {
|
|
return null;
|
|
}
|
|
foundparen = true;
|
|
}
|
|
String num = str.substring(0, index);
|
|
try {
|
|
coords[i] = Double.parseDouble(num);
|
|
} catch (NumberFormatException nfe) {
|
|
return null;
|
|
}
|
|
str = str.substring(index+1);
|
|
}
|
|
if (!foundparen || str.length() > 0) {
|
|
return null;
|
|
}
|
|
Cubic c = new Cubic();
|
|
c.cubic.setCurve(coords[0], coords[1],
|
|
coords[2], coords[3],
|
|
coords[4], coords[5],
|
|
coords[6], coords[7]);
|
|
return c;
|
|
}
|
|
|
|
private CubicCurve2D cubic = new CubicCurve2D.Double();
|
|
|
|
public void randomize() {
|
|
cubic.setCurve(randDblCoord(), randDblCoord(),
|
|
randDblCoord(), randDblCoord(),
|
|
randDblCoord(), randDblCoord(),
|
|
randDblCoord(), randDblCoord());
|
|
}
|
|
|
|
public Shape getShape() {
|
|
return cubic;
|
|
}
|
|
|
|
public String toString() {
|
|
return ("Cubic("+
|
|
cubic.getX1()+", "+
|
|
cubic.getY1()+", "+
|
|
cubic.getCtrlX1()+", "+
|
|
cubic.getCtrlY1()+", "+
|
|
cubic.getCtrlX2()+", "+
|
|
cubic.getCtrlY2()+", "+
|
|
cubic.getX2()+", "+
|
|
cubic.getY2()
|
|
+")");
|
|
}
|
|
}
|
|
|
|
public static class Quad extends AnnotatedShapeOp {
|
|
public static Quad tryparse(String str) {
|
|
str = str.trim();
|
|
if (!str.startsWith("Quad(")) {
|
|
return null;
|
|
}
|
|
str = str.substring(5);
|
|
double coords[] = new double[6];
|
|
boolean foundparen = false;
|
|
for (int i = 0; i < coords.length; i++) {
|
|
int index = str.indexOf(",");
|
|
if (index < 0) {
|
|
if (i < coords.length-1) {
|
|
return null;
|
|
}
|
|
index = str.indexOf(")");
|
|
if (index < 0) {
|
|
return null;
|
|
}
|
|
foundparen = true;
|
|
}
|
|
String num = str.substring(0, index);
|
|
try {
|
|
coords[i] = Double.parseDouble(num);
|
|
} catch (NumberFormatException nfe) {
|
|
return null;
|
|
}
|
|
str = str.substring(index+1);
|
|
}
|
|
if (!foundparen || str.length() > 0) {
|
|
return null;
|
|
}
|
|
Quad c = new Quad();
|
|
c.quad.setCurve(coords[0], coords[1],
|
|
coords[2], coords[3],
|
|
coords[4], coords[5]);
|
|
return c;
|
|
}
|
|
|
|
private QuadCurve2D quad = new QuadCurve2D.Double();
|
|
|
|
public void randomize() {
|
|
quad.setCurve(randDblCoord(), randDblCoord(),
|
|
randDblCoord(), randDblCoord(),
|
|
randDblCoord(), randDblCoord());
|
|
}
|
|
|
|
public Shape getShape() {
|
|
return quad;
|
|
}
|
|
|
|
public String toString() {
|
|
return ("Quad("+
|
|
quad.getX1()+", "+
|
|
quad.getY1()+", "+
|
|
quad.getCtrlX()+", "+
|
|
quad.getCtrlY()+", "+
|
|
quad.getX2()+", "+
|
|
quad.getY2()
|
|
+")");
|
|
}
|
|
}
|
|
|
|
public static class Poly extends AnnotatedShapeOp {
|
|
public static Poly tryparse(String str) {
|
|
str = str.trim();
|
|
if (!str.startsWith("Poly(")) {
|
|
return null;
|
|
}
|
|
str = str.substring(5);
|
|
Polygon p = new Polygon();
|
|
while (true) {
|
|
int x, y;
|
|
str = str.trim();
|
|
if (str.startsWith(")")) {
|
|
str = str.substring(1);
|
|
break;
|
|
}
|
|
if (p.npoints > 0) {
|
|
if (str.startsWith(",")) {
|
|
str = str.substring(2).trim();
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
if (str.startsWith("[")) {
|
|
str = str.substring(1);
|
|
} else {
|
|
return null;
|
|
}
|
|
int index = str.indexOf(",");
|
|
if (index < 0) {
|
|
return null;
|
|
}
|
|
String num = str.substring(0, index);
|
|
try {
|
|
x = Integer.parseInt(num);
|
|
} catch (NumberFormatException nfe) {
|
|
return null;
|
|
}
|
|
str = str.substring(index+1);
|
|
index = str.indexOf("]");
|
|
if (index < 0) {
|
|
return null;
|
|
}
|
|
num = str.substring(0, index).trim();
|
|
try {
|
|
y = Integer.parseInt(num);
|
|
} catch (NumberFormatException nfe) {
|
|
return null;
|
|
}
|
|
str = str.substring(index+1);
|
|
p.addPoint(x, y);
|
|
}
|
|
if (str.length() > 0) {
|
|
return null;
|
|
}
|
|
if (p.npoints < 3) {
|
|
return null;
|
|
}
|
|
return new Poly(p);
|
|
}
|
|
|
|
private Polygon poly;
|
|
|
|
public Poly() {
|
|
this.poly = new Polygon();
|
|
}
|
|
|
|
private Poly(Polygon p) {
|
|
this.poly = p;
|
|
}
|
|
|
|
public void randomize() {
|
|
poly.reset();
|
|
poly.addPoint(randIntCoord(), randIntCoord());
|
|
poly.addPoint(randIntCoord(), randIntCoord());
|
|
poly.addPoint(randIntCoord(), randIntCoord());
|
|
poly.addPoint(randIntCoord(), randIntCoord());
|
|
poly.addPoint(randIntCoord(), randIntCoord());
|
|
}
|
|
|
|
public Shape getShape() {
|
|
return poly;
|
|
}
|
|
|
|
public String toString() {
|
|
StringBuffer sb = new StringBuffer(100);
|
|
sb.append("Poly(");
|
|
for (int i = 0; i < poly.npoints; i++) {
|
|
if (i != 0) {
|
|
sb.append(", ");
|
|
}
|
|
sb.append("[");
|
|
sb.append(poly.xpoints[i]);
|
|
sb.append(", ");
|
|
sb.append(poly.ypoints[i]);
|
|
sb.append("]");
|
|
}
|
|
sb.append(")");
|
|
return sb.toString();
|
|
}
|
|
}
|
|
|
|
public static class Path extends AnnotatedShapeOp {
|
|
public static Path tryparse(String str) {
|
|
str = str.trim();
|
|
if (!str.startsWith("Path(")) {
|
|
return null;
|
|
}
|
|
str = str.substring(5);
|
|
GeneralPath gp = new GeneralPath();
|
|
float coords[] = new float[6];
|
|
int numsegs = 0;
|
|
while (true) {
|
|
int type;
|
|
int n;
|
|
str = str.trim();
|
|
if (str.startsWith(")")) {
|
|
str = str.substring(1);
|
|
break;
|
|
}
|
|
if (str.startsWith("M[")) {
|
|
type = PathIterator.SEG_MOVETO;
|
|
n = 2;
|
|
} else if (str.startsWith("L[")) {
|
|
type = PathIterator.SEG_LINETO;
|
|
n = 2;
|
|
} else if (str.startsWith("Q[")) {
|
|
type = PathIterator.SEG_QUADTO;
|
|
n = 4;
|
|
} else if (str.startsWith("C[")) {
|
|
type = PathIterator.SEG_CUBICTO;
|
|
n = 6;
|
|
} else if (str.startsWith("E[")) {
|
|
type = PathIterator.SEG_CLOSE;
|
|
n = 0;
|
|
} else {
|
|
return null;
|
|
}
|
|
str = str.substring(2);
|
|
if (n == 0) {
|
|
if (str.startsWith("]")) {
|
|
str = str.substring(1);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
for (int i = 0; i < n; i++) {
|
|
int index;
|
|
if (i < n-1) {
|
|
index = str.indexOf(",");
|
|
} else {
|
|
index = str.indexOf("]");
|
|
}
|
|
if (index < 0) {
|
|
return null;
|
|
}
|
|
String num = str.substring(0, index);
|
|
try {
|
|
coords[i] = Float.parseFloat(num);
|
|
} catch (NumberFormatException nfe) {
|
|
return null;
|
|
}
|
|
str = str.substring(index+1).trim();
|
|
}
|
|
switch (type) {
|
|
case PathIterator.SEG_MOVETO:
|
|
gp.moveTo(coords[0], coords[1]);
|
|
break;
|
|
case PathIterator.SEG_LINETO:
|
|
gp.lineTo(coords[0], coords[1]);
|
|
break;
|
|
case PathIterator.SEG_QUADTO:
|
|
gp.quadTo(coords[0], coords[1],
|
|
coords[2], coords[3]);
|
|
break;
|
|
case PathIterator.SEG_CUBICTO:
|
|
gp.curveTo(coords[0], coords[1],
|
|
coords[2], coords[3],
|
|
coords[4], coords[5]);
|
|
break;
|
|
case PathIterator.SEG_CLOSE:
|
|
gp.closePath();
|
|
break;
|
|
}
|
|
numsegs++;
|
|
}
|
|
if (str.length() > 0) {
|
|
return null;
|
|
}
|
|
if (numsegs < 2) {
|
|
return null;
|
|
}
|
|
return new Path(gp);
|
|
}
|
|
|
|
private GeneralPath path;
|
|
|
|
public Path() {
|
|
this.path = new GeneralPath();
|
|
}
|
|
|
|
private Path(GeneralPath gp) {
|
|
this.path = gp;
|
|
}
|
|
|
|
public void randomize() {
|
|
path.reset();
|
|
path.moveTo(randFltCoord(), randFltCoord());
|
|
for (int i = randInt(5)+3; i > 0; --i) {
|
|
switch(randInt(5)) {
|
|
case 0:
|
|
path.moveTo(randFltCoord(), randFltCoord());
|
|
break;
|
|
case 1:
|
|
path.lineTo(randFltCoord(), randFltCoord());
|
|
break;
|
|
case 2:
|
|
path.quadTo(randFltCoord(), randFltCoord(),
|
|
randFltCoord(), randFltCoord());
|
|
break;
|
|
case 3:
|
|
path.curveTo(randFltCoord(), randFltCoord(),
|
|
randFltCoord(), randFltCoord(),
|
|
randFltCoord(), randFltCoord());
|
|
break;
|
|
case 4:
|
|
path.closePath();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public Shape getShape() {
|
|
return path;
|
|
}
|
|
|
|
public String toString() {
|
|
StringBuffer sb = new StringBuffer(100);
|
|
sb.append("Path(");
|
|
PathIterator pi = path.getPathIterator(null);
|
|
float coords[] = new float[6];
|
|
boolean first = true;
|
|
while (!pi.isDone()) {
|
|
int n;
|
|
char c;
|
|
switch(pi.currentSegment(coords)) {
|
|
case PathIterator.SEG_MOVETO:
|
|
c = 'M';
|
|
n = 2;
|
|
break;
|
|
case PathIterator.SEG_LINETO:
|
|
c = 'L';
|
|
n = 2;
|
|
break;
|
|
case PathIterator.SEG_QUADTO:
|
|
c = 'Q';
|
|
n = 4;
|
|
break;
|
|
case PathIterator.SEG_CUBICTO:
|
|
c = 'C';
|
|
n = 6;
|
|
break;
|
|
case PathIterator.SEG_CLOSE:
|
|
c = 'E';
|
|
n = 0;
|
|
break;
|
|
default:
|
|
throw new InternalError("Unknown segment!");
|
|
}
|
|
sb.append(c);
|
|
sb.append("[");
|
|
for (int i = 0; i < n; i++) {
|
|
if (i != 0) {
|
|
sb.append(",");
|
|
}
|
|
sb.append(coords[i]);
|
|
}
|
|
sb.append("]");
|
|
pi.next();
|
|
}
|
|
sb.append(")");
|
|
return sb.toString();
|
|
}
|
|
}
|
|
|
|
public static class Rect extends AnnotatedShapeOp {
|
|
public static Rect tryparse(String str) {
|
|
str = str.trim();
|
|
if (!str.startsWith("Rect(")) {
|
|
return null;
|
|
}
|
|
str = str.substring(5);
|
|
double coords[] = new double[4];
|
|
boolean foundparen = false;
|
|
for (int i = 0; i < coords.length; i++) {
|
|
int index = str.indexOf(",");
|
|
if (index < 0) {
|
|
if (i < coords.length-1) {
|
|
return null;
|
|
}
|
|
index = str.indexOf(")");
|
|
if (index < 0) {
|
|
return null;
|
|
}
|
|
foundparen = true;
|
|
}
|
|
String num = str.substring(0, index);
|
|
try {
|
|
coords[i] = Double.parseDouble(num);
|
|
} catch (NumberFormatException nfe) {
|
|
return null;
|
|
}
|
|
str = str.substring(index+1);
|
|
}
|
|
if (!foundparen || str.length() > 0) {
|
|
return null;
|
|
}
|
|
Rect r = new Rect();
|
|
r.rect.setRect(coords[0], coords[1],
|
|
coords[2], coords[3]);
|
|
return r;
|
|
}
|
|
|
|
private Rectangle2D rect = new Rectangle2D.Double();
|
|
|
|
public void randomize() {
|
|
rect.setRect(randDblCoord(), randDblCoord(),
|
|
randDblCoord(), randDblCoord());
|
|
}
|
|
|
|
public Shape getShape() {
|
|
return rect;
|
|
}
|
|
|
|
public String toString() {
|
|
return ("Rect("+
|
|
rect.getX()+", "+
|
|
rect.getY()+", "+
|
|
rect.getWidth()+", "+
|
|
rect.getHeight()
|
|
+")");
|
|
}
|
|
}
|
|
|
|
public static class Line extends AnnotatedShapeOp {
|
|
public static Line tryparse(String str) {
|
|
str = str.trim();
|
|
if (!str.startsWith("Line(")) {
|
|
return null;
|
|
}
|
|
str = str.substring(5);
|
|
double coords[] = new double[4];
|
|
boolean foundparen = false;
|
|
for (int i = 0; i < coords.length; i++) {
|
|
int index = str.indexOf(",");
|
|
if (index < 0) {
|
|
if (i < coords.length-1) {
|
|
return null;
|
|
}
|
|
index = str.indexOf(")");
|
|
if (index < 0) {
|
|
return null;
|
|
}
|
|
foundparen = true;
|
|
}
|
|
String num = str.substring(0, index);
|
|
try {
|
|
coords[i] = Double.parseDouble(num);
|
|
} catch (NumberFormatException nfe) {
|
|
return null;
|
|
}
|
|
str = str.substring(index+1);
|
|
}
|
|
if (!foundparen || str.length() > 0) {
|
|
return null;
|
|
}
|
|
Line l = new Line();
|
|
l.line.setLine(coords[0], coords[1],
|
|
coords[2], coords[3]);
|
|
return l;
|
|
}
|
|
|
|
private Line2D line = new Line2D.Double();
|
|
|
|
public void randomize() {
|
|
line.setLine(randDblCoord(), randDblCoord(),
|
|
randDblCoord(), randDblCoord());
|
|
}
|
|
|
|
public Shape getShape() {
|
|
return line;
|
|
}
|
|
|
|
public String toString() {
|
|
return ("Line("+
|
|
line.getX1()+", "+
|
|
line.getY1()+", "+
|
|
line.getX2()+", "+
|
|
line.getY2()
|
|
+")");
|
|
}
|
|
}
|
|
|
|
public static class RectMethod extends AnnotatedRenderOp {
|
|
public static RectMethod tryparse(String str) {
|
|
str = str.trim();
|
|
if (!str.startsWith("RectMethod(")) {
|
|
return null;
|
|
}
|
|
str = str.substring(11);
|
|
int coords[] = new int[4];
|
|
boolean foundparen = false;
|
|
for (int i = 0; i < coords.length; i++) {
|
|
int index = str.indexOf(",");
|
|
if (index < 0) {
|
|
if (i < coords.length-1) {
|
|
return null;
|
|
}
|
|
index = str.indexOf(")");
|
|
if (index < 0) {
|
|
return null;
|
|
}
|
|
foundparen = true;
|
|
}
|
|
String num = str.substring(0, index).trim();
|
|
try {
|
|
coords[i] = Integer.parseInt(num);
|
|
} catch (NumberFormatException nfe) {
|
|
return null;
|
|
}
|
|
str = str.substring(index+1);
|
|
}
|
|
if (!foundparen || str.length() > 0) {
|
|
return null;
|
|
}
|
|
RectMethod rm = new RectMethod();
|
|
rm.rect.setBounds(coords[0], coords[1],
|
|
coords[2], coords[3]);
|
|
return rm;
|
|
}
|
|
|
|
private Rectangle rect = new Rectangle();
|
|
|
|
public void randomize() {
|
|
rect.setBounds(randIntCoord(), randIntCoord(),
|
|
randIntCoord(), randIntCoord());
|
|
}
|
|
|
|
public void fill(Graphics2D g2d) {
|
|
g2d.fillRect(rect.x, rect.y, rect.width, rect.height);
|
|
}
|
|
|
|
public void draw(Graphics2D g2d) {
|
|
g2d.drawRect(rect.x, rect.y, rect.width, rect.height);
|
|
}
|
|
|
|
public String toString() {
|
|
return ("RectMethod("+
|
|
rect.x+", "+
|
|
rect.y+", "+
|
|
rect.width+", "+
|
|
rect.height
|
|
+")");
|
|
}
|
|
}
|
|
|
|
public static class LineMethod extends AnnotatedRenderOp {
|
|
public static LineMethod tryparse(String str) {
|
|
str = str.trim();
|
|
if (!str.startsWith("LineMethod(")) {
|
|
return null;
|
|
}
|
|
str = str.substring(11);
|
|
int coords[] = new int[4];
|
|
boolean foundparen = false;
|
|
for (int i = 0; i < coords.length; i++) {
|
|
int index = str.indexOf(",");
|
|
if (index < 0) {
|
|
if (i < coords.length-1) {
|
|
return null;
|
|
}
|
|
index = str.indexOf(")");
|
|
if (index < 0) {
|
|
return null;
|
|
}
|
|
foundparen = true;
|
|
}
|
|
String num = str.substring(0, index).trim();
|
|
try {
|
|
coords[i] = Integer.parseInt(num);
|
|
} catch (NumberFormatException nfe) {
|
|
return null;
|
|
}
|
|
str = str.substring(index+1);
|
|
}
|
|
if (!foundparen || str.length() > 0) {
|
|
return null;
|
|
}
|
|
LineMethod lm = new LineMethod();
|
|
lm.line = coords;
|
|
return lm;
|
|
}
|
|
|
|
private int line[] = new int[4];
|
|
|
|
public void randomize() {
|
|
line[0] = randIntCoord();
|
|
line[1] = randIntCoord();
|
|
line[2] = randIntCoord();
|
|
line[3] = randIntCoord();
|
|
}
|
|
|
|
public void fill(Graphics2D g2d) {
|
|
}
|
|
|
|
public void draw(Graphics2D g2d) {
|
|
g2d.drawLine(line[0], line[1], line[2], line[3]);
|
|
}
|
|
|
|
public String toString() {
|
|
return ("LineMethod("+
|
|
line[0]+", "+
|
|
line[1]+", "+
|
|
line[2]+", "+
|
|
line[3]
|
|
+")");
|
|
}
|
|
}
|
|
|
|
public static class ErrorWindow extends Frame {
|
|
ImageCanvas unclipped;
|
|
ImageCanvas reference;
|
|
ImageCanvas actual;
|
|
ImageCanvas diff;
|
|
|
|
public ErrorWindow() {
|
|
super("Error Comparison Window");
|
|
|
|
unclipped = new ImageCanvas();
|
|
reference = new ImageCanvas();
|
|
actual = new ImageCanvas();
|
|
diff = new ImageCanvas();
|
|
|
|
setLayout(new SmartGridLayout(0, 2, 5, 5));
|
|
addImagePanel(unclipped, "Unclipped rendering");
|
|
addImagePanel(reference, "Clipped reference");
|
|
addImagePanel(actual, "Actual clipped");
|
|
addImagePanel(diff, "Difference");
|
|
|
|
addWindowListener(new WindowAdapter() {
|
|
public void windowClosing(WindowEvent e) {
|
|
setVisible(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
public void addImagePanel(ImageCanvas ic, String label) {
|
|
add(ic);
|
|
add(new Label(label));
|
|
}
|
|
|
|
public void setImages(BufferedImage imgref, BufferedImage imgtst) {
|
|
unclipped.setImage(imgref);
|
|
reference.setReference(imgref);
|
|
actual.setImage(imgtst);
|
|
diff.setDiff(reference.getImage(), imgtst);
|
|
invalidate();
|
|
pack();
|
|
repaint();
|
|
}
|
|
|
|
public void setVisible(boolean vis) {
|
|
super.setVisible(vis);
|
|
synchronized (this) {
|
|
notifyAll();
|
|
}
|
|
}
|
|
|
|
public synchronized void waitForHide() {
|
|
while (isShowing()) {
|
|
try {
|
|
wait();
|
|
} catch (InterruptedException e) {
|
|
System.exit(2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class SmartGridLayout implements LayoutManager {
|
|
int rows;
|
|
int cols;
|
|
int hgap;
|
|
int vgap;
|
|
|
|
public SmartGridLayout(int r, int c, int h, int v) {
|
|
this.rows = r;
|
|
this.cols = c;
|
|
this.hgap = h;
|
|
this.vgap = v;
|
|
}
|
|
|
|
public void addLayoutComponent(String name, Component comp) {
|
|
}
|
|
|
|
public void removeLayoutComponent(Component comp) {
|
|
}
|
|
|
|
public int[][] getGridSizes(Container parent, boolean min) {
|
|
int ncomponents = parent.getComponentCount();
|
|
int nrows = rows;
|
|
int ncols = cols;
|
|
|
|
if (nrows > 0) {
|
|
ncols = (ncomponents + nrows - 1) / nrows;
|
|
} else {
|
|
nrows = (ncomponents + ncols - 1) / ncols;
|
|
}
|
|
int widths[] = new int[ncols+1];
|
|
int heights[] = new int[nrows+1];
|
|
int x = 0;
|
|
int y = 0;
|
|
for (int i = 0 ; i < ncomponents ; i++) {
|
|
Component comp = parent.getComponent(i);
|
|
Dimension d = (min
|
|
? comp.getMinimumSize()
|
|
: comp.getPreferredSize());
|
|
if (widths[x] < d.width) {
|
|
widths[x] = d.width;
|
|
}
|
|
if (heights[y] < d.height) {
|
|
heights[y] = d.height;
|
|
}
|
|
x++;
|
|
if (x >= ncols) {
|
|
x = 0;
|
|
y++;
|
|
}
|
|
}
|
|
for (int i = 0; i < ncols; i++) {
|
|
widths[ncols] += widths[i];
|
|
}
|
|
for (int i = 0; i < nrows; i++) {
|
|
heights[nrows] += heights[i];
|
|
}
|
|
return new int[][] { widths, heights };
|
|
}
|
|
|
|
public Dimension getSize(Container parent, boolean min) {
|
|
int sizes[][] = getGridSizes(parent, min);
|
|
int widths[] = sizes[0];
|
|
int heights[] = sizes[1];
|
|
int nrows = heights.length-1;
|
|
int ncols = widths.length-1;
|
|
int w = widths[ncols];
|
|
int h = heights[nrows];
|
|
Insets insets = parent.getInsets();
|
|
return new Dimension(insets.left+insets.right + w+(ncols+1)*hgap,
|
|
insets.top+insets.bottom + h+(nrows+1)*vgap);
|
|
}
|
|
|
|
public Dimension preferredLayoutSize(Container parent) {
|
|
return getSize(parent, false);
|
|
}
|
|
|
|
public Dimension minimumLayoutSize(Container parent) {
|
|
return getSize(parent, true);
|
|
}
|
|
|
|
public void layoutContainer(Container parent) {
|
|
int pref[][] = getGridSizes(parent, false);
|
|
int min[][] = getGridSizes(parent, true);
|
|
int minwidths[] = min[0];
|
|
int minheights[] = min[1];
|
|
int prefwidths[] = pref[0];
|
|
int prefheights[] = pref[1];
|
|
int nrows = minheights.length - 1;
|
|
int ncols = minwidths.length - 1;
|
|
Insets insets = parent.getInsets();
|
|
int w = parent.getWidth() - insets.left - insets.right;
|
|
int h = parent.getHeight() - insets.top - insets.bottom;
|
|
w = w - (ncols+1)*hgap;
|
|
h = h - (nrows+1)*vgap;
|
|
int widths[] = calculateSizes(w, ncols, minwidths, prefwidths);
|
|
int heights[] = calculateSizes(h, nrows, minheights, prefheights);
|
|
int ncomponents = parent.getComponentCount();
|
|
int x = insets.left + hgap;
|
|
int y = insets.top + vgap;
|
|
int r = 0;
|
|
int c = 0;
|
|
for (int i = 0; i < ncomponents; i++) {
|
|
parent.getComponent(i).setBounds(x, y, widths[c], heights[r]);
|
|
x += widths[c++] + hgap;
|
|
if (c >= ncols) {
|
|
c = 0;
|
|
x = insets.left + hgap;
|
|
y += heights[r++] + vgap;
|
|
if (r >= nrows) {
|
|
// just in case
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static int[] calculateSizes(int total, int num,
|
|
int minsizes[], int prefsizes[])
|
|
{
|
|
if (total <= minsizes[num]) {
|
|
return minsizes;
|
|
}
|
|
if (total >= prefsizes[num]) {
|
|
return prefsizes;
|
|
}
|
|
int sizes[] = new int[total];
|
|
int prevhappy = 0;
|
|
int nhappy = 0;
|
|
int happysize = 0;
|
|
do {
|
|
int addsize = (total - happysize) / (num - nhappy);
|
|
happysize = 0;
|
|
for (int i = 0; i < num; i++) {
|
|
if (sizes[i] >= prefsizes[i] ||
|
|
minsizes[i] + addsize > prefsizes[i])
|
|
{
|
|
happysize += (sizes[i] = prefsizes[i]);
|
|
nhappy++;
|
|
} else {
|
|
sizes[i] = minsizes[i] + addsize;
|
|
}
|
|
}
|
|
} while (nhappy < num && nhappy > prevhappy);
|
|
return sizes;
|
|
}
|
|
}
|
|
|
|
public static class ImageCanvas extends Canvas {
|
|
BufferedImage image;
|
|
|
|
public void setImage(BufferedImage img) {
|
|
this.image = img;
|
|
}
|
|
|
|
public BufferedImage getImage() {
|
|
return image;
|
|
}
|
|
|
|
public void checkImage(int w, int h) {
|
|
if (image == null ||
|
|
image.getWidth() < w ||
|
|
image.getHeight() < h)
|
|
{
|
|
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
|
|
}
|
|
}
|
|
|
|
public void setReference(BufferedImage img) {
|
|
checkImage(img.getWidth(), img.getHeight());
|
|
Graphics g = image.createGraphics();
|
|
g.drawImage(img, 0, 0, null);
|
|
g.setColor(Color.white);
|
|
g.fillRect(0, 0, 30, 10);
|
|
g.fillRect(30, 0, 10, 30);
|
|
g.fillRect(10, 30, 30, 10);
|
|
g.fillRect(0, 10, 10, 30);
|
|
g.dispose();
|
|
}
|
|
|
|
public void setDiff(BufferedImage imgref, BufferedImage imgtst) {
|
|
int w = Math.max(imgref.getWidth(), imgtst.getWidth());
|
|
int h = Math.max(imgref.getHeight(), imgtst.getHeight());
|
|
checkImage(w, h);
|
|
Graphics g = image.createGraphics();
|
|
g.drawImage(imgref, 0, 0, null);
|
|
g.setXORMode(Color.white);
|
|
g.drawImage(imgtst, 0, 0, null);
|
|
g.setPaintMode();
|
|
g.setColor(new Color(1f, 1f, 0f, 0.25f));
|
|
g.fillRect(10, 10, 20, 20);
|
|
g.setColor(new Color(1f, 0f, 0f, 0.25f));
|
|
g.fillRect(0, 0, 30, 10);
|
|
g.fillRect(30, 0, 10, 30);
|
|
g.fillRect(10, 30, 30, 10);
|
|
g.fillRect(0, 10, 10, 30);
|
|
g.dispose();
|
|
}
|
|
|
|
public Dimension getPreferredSize() {
|
|
if (image == null) {
|
|
return new Dimension();
|
|
} else {
|
|
return new Dimension(image.getWidth(), image.getHeight());
|
|
}
|
|
}
|
|
|
|
public void paint(Graphics g) {
|
|
g.drawImage(image, 0, 0, null);
|
|
}
|
|
}
|
|
}
|