c56c69ed3e
Reviewed-by: psadhukhan
519 lines
18 KiB
Java
519 lines
18 KiB
Java
/*
|
|
* 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);
|
|
}
|
|
});
|
|
}
|
|
};
|