8285604: closed sun/java2d/GdiRendering/ClipShapeRendering.java failed with "Incorrect color ffeeeeee instead of ff0000ff in pixel (100, 100)"
Reviewed-by: psadhukhan
This commit is contained in:
parent
6fd1442123
commit
c56c69ed3e
518
test/jdk/sun/java2d/GdiRendering/ClipShapeRendering.java
Normal file
518
test/jdk/sun/java2d/GdiRendering/ClipShapeRendering.java
Normal file
@ -0,0 +1,518 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2022, 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 4925447 4887054 8285604
|
||||
* @key headful
|
||||
* @summary verifies that most basic rendering operations going are successfully
|
||||
* clipped against a complex clip shape
|
||||
* @run main ClipShapeRendering
|
||||
*/
|
||||
|
||||
/**
|
||||
* This test creates a complex clip shape (basically, a rectangular hole
|
||||
* cut out of the center of the rendering area) and then cycles through
|
||||
* various rendering primitives (image copies, lines, text, and shapes)
|
||||
* under various situations (default, scaled transform, and wide lines).
|
||||
* After all of that, Robot is used to check whether the clip shape has
|
||||
* been disturbed by any of the rendering (no pixels from the rendering
|
||||
* operations should have done anything inside the clipped-out area); the
|
||||
* test passes or fails based on whether the clip shape is undisturbed.
|
||||
*
|
||||
* There is a performance-test version of this app which runs all of the
|
||||
* tests in loops and times the results. This can be useful to see, for
|
||||
* example, the difference in performance between old and new internal
|
||||
* implementations of this clip-shape situation. To run the performance
|
||||
* test, run ClipShapeRendering -perf.
|
||||
*/
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Robot;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DirectColorModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
|
||||
public class ClipShapeRendering extends Frame {
|
||||
BufferedImage image;
|
||||
BufferedImage imageBM;
|
||||
|
||||
static Image offScreenImage;
|
||||
static boolean timeToRun = false;
|
||||
static Color imageColor = Color.red;
|
||||
static Color fillColor = Color.blue;
|
||||
static boolean perfMode = false;
|
||||
static boolean showCapture = false;
|
||||
static Rectangle clipRect = new Rectangle(100, 100, 100, 100);
|
||||
|
||||
// move away from cursor
|
||||
private final static int OFFSET_X = 20;
|
||||
private final static int OFFSET_Y = 20;
|
||||
|
||||
public ClipShapeRendering() {
|
||||
super("On-screen rendering test frame");
|
||||
}
|
||||
|
||||
public void initImages(Color imageColor) {
|
||||
int w = getWidth();
|
||||
int h = getHeight();
|
||||
|
||||
ColorModel cm = new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);
|
||||
WritableRaster wr =
|
||||
cm.createCompatibleWritableRaster(w, h);
|
||||
imageBM = new BufferedImage(cm, wr,
|
||||
cm.isAlphaPremultiplied(), null);
|
||||
Graphics g2 = imageBM.createGraphics();
|
||||
g2.setColor(imageColor);
|
||||
g2.fillRect(0, 0, w, h);
|
||||
|
||||
image = new BufferedImage(w, h,
|
||||
BufferedImage.TYPE_INT_RGB);
|
||||
g2 = image.createGraphics();
|
||||
g2.setColor(imageColor);
|
||||
g2.fillRect(0,0, w, h);
|
||||
g2.dispose();
|
||||
|
||||
offScreenImage = createImage(w, h);
|
||||
}
|
||||
|
||||
public void paint(Graphics g) {
|
||||
synchronized (this) {
|
||||
timeToRun = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void runTests() {
|
||||
initImages(imageColor);
|
||||
|
||||
// run off-screen test
|
||||
System.out.println("Running OFF-SCREEN tests..");
|
||||
runTest(offScreenImage.getGraphics());
|
||||
|
||||
// run on-screen test
|
||||
System.out.println("Running ON-SCREEN tests..");
|
||||
runTest(getGraphics());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set various parameters on the Graphics object and call the
|
||||
* rendering loop with each variation
|
||||
*/
|
||||
public void runTest(Graphics g) {
|
||||
int w = getWidth();
|
||||
int h = getHeight();
|
||||
Area area = new Area( new Rectangle(0,0, w, h));
|
||||
area.subtract(new Area(clipRect));
|
||||
// Fill completely with background color
|
||||
g.setColor(fillColor);
|
||||
g.fillRect(0, 0, w, h);
|
||||
|
||||
// Set the clip shape
|
||||
g.setClip(area);
|
||||
|
||||
// Now perform various rendering operations
|
||||
g.setColor(Color.black);
|
||||
Graphics2D g2 = (Graphics2D)g;
|
||||
if (perfMode) {
|
||||
System.out.println("Default Graphics Results:");
|
||||
System.out.println("-------------------------");
|
||||
}
|
||||
renderingLoop(g2);
|
||||
|
||||
if (perfMode) {
|
||||
System.out.println("Scaling Transform Results:");
|
||||
System.out.println("-------------------------");
|
||||
}
|
||||
AffineTransform oldXform = g2.getTransform();
|
||||
g2.scale(.9, 1.15);
|
||||
renderingLoop(g2);
|
||||
g2.setTransform(oldXform);
|
||||
|
||||
if (perfMode) {
|
||||
System.out.println("Wide Lines Results:");
|
||||
System.out.println("-------------------");
|
||||
}
|
||||
Stroke oldStroke = g2.getStroke();
|
||||
g2.setStroke(new BasicStroke(5.0f));
|
||||
renderingLoop(g2);
|
||||
g2.setStroke(oldStroke);
|
||||
}
|
||||
|
||||
public void renderingLoop(Graphics2D g) {
|
||||
int numReps = 1;
|
||||
int numTextReps = 1;
|
||||
long start, end;
|
||||
if (perfMode) {
|
||||
numReps = 1000;
|
||||
numTextReps = 50;
|
||||
}
|
||||
int w = getWidth();
|
||||
int h = getHeight();
|
||||
|
||||
// Image copies
|
||||
robot.waitForIdle();
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < numReps; ++i) {
|
||||
g.drawImage(image, 0, 0, null);
|
||||
g.drawImage(image, -10, -10, null);
|
||||
g.drawImage(image, 50, 50, null);
|
||||
g.drawImage(image, 40, 10, null);
|
||||
}
|
||||
for (int i = 0; i < numReps; ++i) {
|
||||
g.drawImage(imageBM, 0, 0, Color.yellow, null);
|
||||
g.drawImage(imageBM, -10, -10, Color.yellow, null);
|
||||
g.drawImage(imageBM, 50, 50, Color.yellow, null);
|
||||
g.drawImage(imageBM, 40, 10, Color.yellow, null);
|
||||
}
|
||||
robot.waitForIdle();
|
||||
end = System.currentTimeMillis();
|
||||
if (perfMode) {
|
||||
System.out.println("Image Copies : " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
// Image scales
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < numReps; ++i) {
|
||||
g.drawImage(image, 0, 0, 500, 500, null);
|
||||
}
|
||||
robot.waitForIdle();
|
||||
end = System.currentTimeMillis();
|
||||
if (perfMode) {
|
||||
System.out.println("Image scales : " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
// Lines
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < numReps; ++i) {
|
||||
g.drawLine(0, 0, w, h);
|
||||
g.drawLine(0, h, w, 0);
|
||||
g.drawLine(0, h / 2, w, h / 2);
|
||||
g.drawLine(w / 2, 0, w / 2, h);
|
||||
}
|
||||
robot.waitForIdle();
|
||||
end = System.currentTimeMillis();
|
||||
if (perfMode) {
|
||||
System.out.println("drawLine : " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
// Text
|
||||
|
||||
// Non-AA
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < numTextReps; ++i) {
|
||||
for (int x = 0; x < w; x += 20) {
|
||||
for (int y = 0; y < h; y += 17) {
|
||||
g.drawString("This is a string, this is only a string", x,
|
||||
y);
|
||||
}
|
||||
}
|
||||
}
|
||||
robot.waitForIdle();
|
||||
end = System.currentTimeMillis();
|
||||
if (perfMode) {
|
||||
System.out.println("Text Non-AA : " + (end - start) + " ms");
|
||||
}
|
||||
// Anti-Aliased
|
||||
Graphics2D g2 = (Graphics2D)g;
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < numTextReps; ++i) {
|
||||
for (int x = 0; x < w; x += 20) {
|
||||
for (int y = 0; y < h; y += 17) {
|
||||
g.drawString("This is a string, this is only a string", x,
|
||||
y);
|
||||
}
|
||||
}
|
||||
}
|
||||
robot.waitForIdle();
|
||||
end = System.currentTimeMillis();
|
||||
if (perfMode) {
|
||||
System.out.println("Text General AA: " + (end - start) + " ms");
|
||||
}
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_OFF);
|
||||
// Text AA
|
||||
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < numTextReps; ++i) {
|
||||
for (int x = 0; x < w; x += 20) {
|
||||
for (int y = 0; y < h; y += 17) {
|
||||
g.drawString("This is a string, this is only a string", x,
|
||||
y);
|
||||
}
|
||||
}
|
||||
}
|
||||
robot.waitForIdle();
|
||||
end = System.currentTimeMillis();
|
||||
if (perfMode) {
|
||||
System.out.println("Text textAA : " + (end - start) + " ms");
|
||||
}
|
||||
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
|
||||
|
||||
// Arcs
|
||||
start = System.currentTimeMillis();
|
||||
if (numReps > 1) {
|
||||
numReps /= 10;
|
||||
}
|
||||
for (int i = 0; i < numReps; ++i) {
|
||||
for (int x = 0; x < w; x += 20) {
|
||||
for (int y = 0; y < h; y += 17) {
|
||||
g.drawArc(x, y, 30, 30, 0, 45);
|
||||
g.fillArc(x, y, 25, 25, 0, 45);
|
||||
}
|
||||
}
|
||||
}
|
||||
robot.waitForIdle();
|
||||
end = System.currentTimeMillis();
|
||||
if (perfMode) {
|
||||
System.out.println("arcs : " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
// Ovals
|
||||
start = System.currentTimeMillis();
|
||||
if (numReps > 1) {
|
||||
numReps /= 10;
|
||||
}
|
||||
for (int i = 0; i < numReps; ++i) {
|
||||
for (int x = 0; x < w; x += 20) {
|
||||
for (int y = 0; y < h; y += 17) {
|
||||
g.drawOval(x, y, 20, 20);
|
||||
g.fillOval(x, y, 15, 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
robot.waitForIdle();
|
||||
end = System.currentTimeMillis();
|
||||
if (perfMode) {
|
||||
System.out.println("ovals : " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
// Rects
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < numReps; ++i) {
|
||||
for (int x = 0; x < w; x += 20) {
|
||||
for (int y = 0; y < h; y += 17) {
|
||||
g.drawRect(x, y, 20, 20);
|
||||
g.fillRect(x, y, 18, 18);
|
||||
}
|
||||
}
|
||||
}
|
||||
robot.waitForIdle();
|
||||
end = System.currentTimeMillis();
|
||||
if (perfMode) {
|
||||
System.out.println("rects : " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
// GeneralPath rendering
|
||||
GeneralPath drawGP = new GeneralPath();
|
||||
for (int i = 0; i < 30; ++i) {
|
||||
Rectangle rect = new Rectangle(5 * i, 2 * i, 27, 19);
|
||||
drawGP.append(rect, false);
|
||||
}
|
||||
GeneralPath fillGP = new GeneralPath();
|
||||
for (int i = 0; i < 30; ++i) {
|
||||
Rectangle rect = new Rectangle(5 * i, 100 + 2 * i, 27, 19);
|
||||
fillGP.append(rect, false);
|
||||
}
|
||||
Graphics2D g2d = (Graphics2D)g;
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < numReps; ++i) {
|
||||
g2d.draw(drawGP);
|
||||
g2d.fill(fillGP);
|
||||
}
|
||||
robot.waitForIdle();
|
||||
end = System.currentTimeMillis();
|
||||
if (perfMode) {
|
||||
System.out.println("GeneralPath : " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void usage() {
|
||||
System.err.println("java ClipShapeRendering [-perf] [-show]");
|
||||
System.err.println(" -perf : runs performance benchmark (1000 reps)");
|
||||
System.err.println(" -show : shows a frame with captured clip area");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
public static boolean checkResult(BufferedImage clientPixels) {
|
||||
int pixels[] = new int[clipRect.width * clipRect.height];
|
||||
clientPixels.getRGB(0, 0, clipRect.width,
|
||||
clipRect.height, pixels, 0,
|
||||
clipRect.width);
|
||||
int pixelIndex = 0;
|
||||
for (int row = 0; row < clipRect.height; ++row) {
|
||||
for (int col = 0; col < clipRect.width; ++col) {
|
||||
if (!(new Color(pixels[pixelIndex])).equals(fillColor)) {
|
||||
System.err.println("Incorrect color " +
|
||||
Integer.toHexString(pixels[pixelIndex]) +
|
||||
" instead of " +
|
||||
Integer.toHexString(fillColor.getRGB()) +
|
||||
" in pixel (" + (clipRect.x + col) +
|
||||
", " + (clipRect.y + row) + ")");
|
||||
return false;
|
||||
}
|
||||
pixelIndex++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static volatile Robot robot;
|
||||
public static void main(String args[]) throws Exception {
|
||||
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
if (args[i].equals("-perf")) {
|
||||
perfMode = true;
|
||||
} else if (args[i].equals("-show")) {
|
||||
showCapture = true;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
robot = new Robot();
|
||||
} catch (AWTException e) {
|
||||
throw new RuntimeException("Can't create robot: " + e);
|
||||
}
|
||||
|
||||
ClipShapeRendering clipTest = new ClipShapeRendering();
|
||||
clipTest.setSize(300, 300);
|
||||
clipTest.setLocationRelativeTo(null);
|
||||
clipTest.setAlwaysOnTop(true);
|
||||
clipTest.setVisible(true);
|
||||
try {
|
||||
synchronized (clipTest) {
|
||||
while (!timeToRun) {
|
||||
clipTest.wait(300);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {}
|
||||
|
||||
clipTest.runTests();
|
||||
|
||||
// check off-screen rendering;
|
||||
BufferedImage offScreenClientPixels =
|
||||
(BufferedImage)clipTest.createImage(clipRect.width,
|
||||
clipRect.height);
|
||||
Graphics clientG = offScreenClientPixels.getGraphics();
|
||||
clientG.drawImage(offScreenImage,
|
||||
0, 0, clipRect.width, clipRect.height,
|
||||
clipRect.x, clipRect.y,
|
||||
clipRect.x + clipRect.width,
|
||||
clipRect.y + clipRect.height,
|
||||
null);
|
||||
if (showCapture) {
|
||||
CaptureFrame f =
|
||||
new CaptureFrame("OffScreen Image", offScreenImage);
|
||||
f.setVisible(true);
|
||||
}
|
||||
|
||||
// check onscreen rendering
|
||||
Point clientLoc = clipTest.getLocationOnScreen();
|
||||
Rectangle r = (Rectangle)clipRect.clone();
|
||||
r.translate(clientLoc.x, clientLoc.y);
|
||||
|
||||
// move mouse cursor away from captured region as in some system
|
||||
// cursor remain visible in composite captured image
|
||||
robot.mouseMove(r.x - OFFSET_X, r.y - OFFSET_Y);
|
||||
robot.waitForIdle();
|
||||
BufferedImage onScreenClientPixels = robot.createScreenCapture(r);
|
||||
try { Thread.sleep(1000); } catch (Exception e) {}
|
||||
if (showCapture) {
|
||||
CaptureFrame f =
|
||||
new CaptureFrame("Onscreen clip area", onScreenClientPixels);
|
||||
f.setVisible(true);
|
||||
} else {
|
||||
clipTest.dispose();
|
||||
}
|
||||
|
||||
|
||||
System.out.print("Checking results for off-screen rendering..");
|
||||
boolean offScreenPassed = checkResult(offScreenClientPixels);
|
||||
System.out.println("done.");
|
||||
|
||||
System.out.print("Checking results for on-screen rendering..");
|
||||
boolean onScreenPassed = checkResult(onScreenClientPixels);
|
||||
System.out.println("done.");
|
||||
if (!offScreenPassed || !onScreenPassed) {
|
||||
javax.imageio.ImageIO.write(offScreenClientPixels, "png", new java.io.File("offscreen.png"));
|
||||
javax.imageio.ImageIO.write(onScreenClientPixels, "png", new java.io.File("onscreen.png"));
|
||||
throw new RuntimeException("Test failed. off-screen: " +
|
||||
(offScreenPassed?"passed":"failed") +
|
||||
" on-screen: " +
|
||||
(onScreenPassed?"passed":"failed"));
|
||||
}
|
||||
System.out.println("Passed");
|
||||
}
|
||||
|
||||
static {
|
||||
System.setProperty("sun.java2d.pmoffscreen", "true");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CaptureFrame extends Frame {
|
||||
static int x = 300, y = 0;
|
||||
Image clientPixels;
|
||||
public CaptureFrame(String title, Image clientPixels) {
|
||||
super("Capture Frame: " + title);
|
||||
this.clientPixels = clientPixels;
|
||||
int w = clientPixels.getWidth(null);
|
||||
int h = clientPixels.getHeight(null);
|
||||
setSize(w, h + 30);
|
||||
setLocation(x, y);
|
||||
x += w;
|
||||
if (x + w > 1024) {
|
||||
x = 300;
|
||||
y += h;
|
||||
}
|
||||
add(new Component() {
|
||||
public void paint(Graphics g) {
|
||||
g.drawImage(CaptureFrame.this.clientPixels, 0, 0, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user