/* * Copyright (c) 2010, 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 5089429 6982632 8145808 @summary Checks that we don't crash if rendering operations and state changes are performed on a graphics context from different threads. @author Dmitri.Trembovetski@sun.com area=Graphics @run main MTGraphicsAccessTest */ import java.awt.*; import java.awt.image.*; import java.awt.geom.*; import java.util.concurrent.atomic.AtomicInteger; public class MTGraphicsAccessTest { // in seconds static final long STANDALONE_RUN_TIME = 20; static final long JTREG_RUN_TIME = 7; static boolean standaloneMode; static boolean allowExceptions = true; static long testRunTime; volatile boolean done; AtomicInteger stillRunning = new AtomicInteger(0); volatile int numexceptions; Graphics2D sharedGraphics; BufferedImage sharedBI = new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB); static final Paint colors[] = { Color.red, new Color(0x7f, 0xff, 0x00, 0x7f), new GradientPaint(0, 0, Color.red, 50, 50, new Color(0x7f, 0xff, 0x00, 0x7f)), }; static final Font fonts[] = { new Font("Dialog", Font.PLAIN, 12), new Font("Dialog", Font.BOLD, 16), new Font("Dialog", Font.ITALIC, 18), }; static final AlphaComposite comps[] = { AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f), AlphaComposite.Src, AlphaComposite.Xor, AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f), null, }; static final Stroke strokes[] = { new BasicStroke(), new BasicStroke(0.0f), new BasicStroke(2.0f), new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL), new BasicStroke(5.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND), new BasicStroke(0.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, new float[]{0,6,0,6}, 0), }; static final AffineTransform transforms[] = { new AffineTransform(), AffineTransform.getRotateInstance(10.0), AffineTransform.getShearInstance(10.0, 4.0), AffineTransform.getScaleInstance(1.1, 1.2), AffineTransform.getScaleInstance(3.0, 2.0), }; public MTGraphicsAccessTest() { BufferedImage bi = new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB); sharedGraphics = (Graphics2D)bi.getGraphics(); done = false; numexceptions = 0; for (int i = 0; i < (standaloneMode ? stateChangers.length : 3); i++) { (new TesterThread(stateChangers[i])).start(); } for (int i = 0; i < (standaloneMode ? renderTests.length : 5); i++) { (new TesterThread(renderTests[i])).start(); } mysleep(testRunTime); done = true; while (stillRunning.get() > 0) { mysleep(500); } if (numexceptions == 0) { System.err.println("Test passed"); } else if (!allowExceptions) { throw new RuntimeException("Test failed with "+ numexceptions+" exceptions"); } else { System.err.println("Test finished with "+ numexceptions+" exceptions"); } } private void mysleep(long time) { try { // add +/-5ms variance to increase randomness Thread.sleep(time + (long)(5 - Math.random()*10)); } catch (InterruptedException e) {}; } public static void usage(String message) { if (message != null) { System.err.println(message); } System.err.println("Usage: MTGraphicsAccessTest [-full] "+ "[-time N/forever] [-help]"); System.err.println(" -full: run full suite of tests "+ "(default: limited number of tests is run)"); System.err.println(" -time N: test duration in seconds/forever"+ " (default: "+JTREG_RUN_TIME+"s for the short suite, "+ STANDALONE_RUN_TIME+"s for the full suite)"); System.err.println(" -help: print this help page"); System.exit(1); } public static void main(String[] args) { boolean testRunSet = false; for (int i = 0; i < args.length; i++) { if ("-full".equals(args[i])) { standaloneMode = true; System.err.println("Running complete list of tests"); } else if ("-noexc".equals(args[i])) { allowExceptions = false; } else if ("-time".equals(args[i])) { try { String time = args[++i]; if ("forever".equals(time)) { testRunTime = (Long.MAX_VALUE - 20)/1000; } else { testRunTime = 1000*Integer.parseInt(time); } testRunSet = true; } catch (NumberFormatException e) { usage("Can't parse number of seconds: " + args[i]); } catch (ArrayIndexOutOfBoundsException e1) { usage("Missing the 'seconds' argument for -time parameter"); } } else if ("-help".equals(args[i])) { usage(null); } else { usage("Unknown argument:" + args[i]); } } if (!testRunSet) { testRunTime = 1000 * (standaloneMode ? STANDALONE_RUN_TIME : JTREG_RUN_TIME); } System.err.println("Approximate test run time: "+ testRunTime/1000+" seconds"); new MTGraphicsAccessTest(); } class TesterThread extends Thread { Runnable testRunnable; public TesterThread(Runnable testRunnable) { stillRunning.incrementAndGet(); this.testRunnable = testRunnable; } public void run() { try { while (!done) { try { testRunnable.run(); yield(); } catch (Throwable t) { numexceptions++; t.printStackTrace(); } } } finally { stillRunning.decrementAndGet(); } } } final Runnable stateChangers[] = { new Runnable() { public void run() { sharedGraphics.setClip(10, 10, 30, 30); mysleep(10); } }, new Runnable() { public void run() { sharedGraphics.setClip(10, 10, 30, 30); mysleep(10); } }, new Runnable() { int c = 0; public void run() { sharedGraphics.setPaint(colors[c++ % colors.length]); mysleep(10); } }, new Runnable() { boolean AA = false; public void run() { if (AA) { sharedGraphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } else { sharedGraphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); } AA = !AA; mysleep(10); } }, new Runnable() { int t = 0; public void run() { sharedGraphics.setTransform( transforms[t++ % transforms.length]); mysleep(10); } }, new Runnable() { int c = 0; public void run() { AlphaComposite comp = comps[c++ % comps.length]; if (comp == null) { sharedGraphics.setXORMode(Color.green); } else { sharedGraphics.setComposite(comp); } mysleep(10); } }, new Runnable() { int s = 0; public void run() { sharedGraphics.setStroke(strokes[s++ % strokes.length]); mysleep(10); } }, new Runnable() { int f = 0; public void run() { sharedGraphics.setFont(fonts[f++ % fonts.length]); mysleep(10); } }, }; final Runnable renderTests[] = { new Runnable() { public void run() { sharedGraphics.drawLine(10, 10, 30, 30); } }, new Runnable() { public void run() { sharedGraphics.drawLine(10, 10, 30, 30); } }, new Runnable() { public void run() { sharedGraphics.drawRect(10, 10, 30, 30); } }, new Runnable() { public void run() { sharedGraphics.fillRect(10, 10, 30, 30); } }, new Runnable() { public void run() { sharedGraphics.drawString("Stuff", 10, 10); } }, new Runnable() { public void run() { sharedGraphics.draw3DRect(10, 10, 30, 30, true); } }, new Runnable() { public void run() { sharedGraphics.drawImage(sharedBI, 10, 10, null); } }, new Runnable() { public void run() { sharedGraphics.fill3DRect(10, 10, 30, 30, false); } }, // REMIND: copyArea doesn't work when transform is set.. // new Runnable() { // public void run() { // sharedGraphics.copyArea(10, 10, 30, 30, 20, 20); // } // }, new Runnable() { public void run() { sharedGraphics.drawRoundRect(10, 10, 30, 30, 20, 20); } }, new Runnable() { public void run() { sharedGraphics.fillRoundRect(10, 10, 30, 30, 20, 20); } }, new Runnable() { public void run() { sharedGraphics.drawArc(10, 10, 30, 30, 0, 90); } }, new Runnable() { public void run() { sharedGraphics.fillArc(10, 10, 30, 30, 0, 90); } }, new Runnable() { public void run() { sharedGraphics.drawOval(10, 10, 30, 30); } }, new Runnable() { public void run() { sharedGraphics.fillOval(10, 10, 30, 30); } } }; }