| /* | |
| * Copyright (c) 2000, 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.Button; | |
| import java.awt.Canvas; | |
| import java.awt.Choice; | |
| import java.awt.Color; | |
| import java.awt.Dimension; | |
| import java.awt.FlowLayout; | |
| import java.awt.FontMetrics; | |
| import java.awt.Frame; | |
| import java.awt.Graphics; | |
| import java.awt.Graphics2D; | |
| import java.awt.GraphicsConfiguration; | |
| import java.awt.GraphicsDevice; | |
| import java.awt.GraphicsEnvironment; | |
| import java.awt.Image; | |
| import java.awt.Label; | |
| import java.awt.LayoutManager; | |
| import java.awt.Panel; | |
| import java.awt.Rectangle; | |
| import java.awt.RenderingHints; | |
| import java.awt.TextField; | |
| import java.awt.event.ActionEvent; | |
| import java.awt.event.ActionListener; | |
| import java.awt.image.ColorModel; | |
| import java.awt.image.MemoryImageSource; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import javax.swing.JFrame; | |
| import jtreg.SkippedException; | |
| /* | |
| * @test | |
| * @bug 4312921 | |
| * @key multimon | |
| * @library /java/awt/regtesthelpers /test/lib | |
| * @build PassFailJFrame | |
| * @summary Tests that no garbage is painted on primary screen with DGA | |
| * @run main/manual MultiScreenTest | |
| */ | |
| public class MultiScreenTest { | |
| static GraphicsEnvironment ge; | |
| static GraphicsDevice[] gs; | |
| public static void main(String[] args) throws Exception { | |
| ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); | |
| gs = ge.getScreenDevices(); | |
| if (gs.length < 2) { | |
| throw new SkippedException("You have only one monitor in your system - test passed"); | |
| } | |
| MultiScreenTest obj = new MultiScreenTest(); | |
| String INSTRUCTIONS = | |
| "This test is to be run only on multiscreen machine. " + | |
| "You have " + gs.length + " monitors in your system.\n" + | |
| "Actively drag the DitherTest frames on the secondary screen and " + | |
| "if you see garbage appearing on your primary screen " + | |
| "test failed otherwise it passed.";; | |
| PassFailJFrame.builder() | |
| .title("MultiScreenTest Instruction") | |
| .instructions(INSTRUCTIONS) | |
| .rows((int) INSTRUCTIONS.lines().count() + 2) | |
| .columns(40) | |
| .testUI(obj::init) | |
| .build() | |
| .awaitAndCheck(); | |
| } | |
| public List<JFrame> init() { | |
| List<JFrame> list = new ArrayList<>(); | |
| for (int j = 0; j < gs.length; j++) { | |
| GraphicsConfiguration[] gc = gs[j].getConfigurations(); | |
| if (gc.length > 0) { | |
| for (int i = 0; i < gc.length / 2; i++) { | |
| JFrame f = new JFrame(gc[i]); //test JFrame( gc ) | |
| GCCanvas c = new GCCanvas(gc[i]);//test canvas( gc ) | |
| Rectangle gcBounds = gc[i].getBounds(); //test getBounds() | |
| int xoffs = gcBounds.x; | |
| int yoffs = gcBounds.y; | |
| f.getContentPane().add(c); | |
| f.setTitle("Screen# " + Integer.toString(j) + ", GC#" + Integer.toString(i)); | |
| f.setSize(300, 200); | |
| f.setLocation(400 + xoffs, (i * 150) + yoffs);//test displaying in right location | |
| list.add(f); | |
| Frame ditherfs = new Frame("DitherTest GC#" + Integer.toString(i), gc[i]); | |
| ditherfs.setLayout(new BorderLayout()); //showDitherTest | |
| DitherTest ditherTest = new DitherTest(gc[i]); | |
| ditherfs.add("Center", ditherTest); | |
| ditherfs.setBounds(300, 200, 300, 200); | |
| ditherfs.setLocation(750 + xoffs, (i * 50) + yoffs); | |
| ditherfs.pack(); | |
| ditherfs.show(); | |
| ditherTest.start(); | |
| } | |
| } | |
| } | |
| return list; | |
| } | |
| } | |
| class GCCanvas extends Canvas { | |
| GraphicsConfiguration gc; | |
| Rectangle bounds; | |
| Graphics g = this.getGraphics(); | |
| Dimension size = getSize(); | |
| public GCCanvas(GraphicsConfiguration gc) { | |
| super(gc); | |
| this.gc = gc; | |
| bounds = gc.getBounds(); | |
| } | |
| public void paint( Graphics _g ) { | |
| Graphics2D g = (Graphics2D) _g; | |
| g.drawRect(0, 0, size.width-1, size.height-1); | |
| g.setColor(Color.lightGray); | |
| g.draw3DRect(1, 1, size.width-3, size.height-3, true); | |
| g.setColor(Color.red); | |
| g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | |
| g.drawString("HELLO!", 110, 10); | |
| g.setColor(Color.blue); | |
| g.drawString("ScreenSize="+Integer.toString(bounds.width)+"X"+ | |
| Integer.toString(bounds.height), 10, 20); | |
| g.setColor(Color.green); | |
| g.drawString(gc.toString(), 10, 30); | |
| g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); | |
| g.setColor(Color.orange); | |
| g.fillRect(40, 20, 50, 50); | |
| g.setColor(Color.red); | |
| g.drawRect(100, 20, 30, 30); | |
| g.setColor(Color.gray); | |
| g.drawLine(220, 20, 280, 40); | |
| g.setColor(Color.cyan); | |
| g.fillArc(150, 30, 30, 30, 0, 200); | |
| } | |
| public Dimension getPreferredSize(){ | |
| return new Dimension(300, 200); | |
| } | |
| } | |
| class DitherCanvas extends Canvas { | |
| Image img; | |
| static String calcString = "Calculating..."; | |
| GraphicsConfiguration mGC; | |
| public DitherCanvas(GraphicsConfiguration gc) { | |
| super(gc); | |
| mGC = gc; | |
| } | |
| public GraphicsConfiguration getGraphicsConfig() { | |
| return mGC; | |
| } | |
| public void paint(Graphics g) { | |
| int w = getSize().width; | |
| int h = getSize().height; | |
| if (img == null) { | |
| super.paint(g); | |
| g.setColor(Color.black); | |
| FontMetrics fm = g.getFontMetrics(); | |
| int x = (w - fm.stringWidth(calcString)) / 2; | |
| int y = h / 2; | |
| g.drawString(calcString, x, y); | |
| } else { | |
| g.drawImage(img, 0, 0, w, h, this); | |
| } | |
| } | |
| public void update(Graphics g) { | |
| paint(g); | |
| } | |
| public Dimension getMinimumSize() { | |
| return new Dimension(20, 20); | |
| } | |
| public Dimension getPreferredSize() { | |
| return new Dimension(200, 200); | |
| } | |
| public Image getImage() { | |
| return img; | |
| } | |
| public void setImage(Image img) { | |
| this.img = img; | |
| paint(getGraphics()); | |
| } | |
| } | |
| class DitherTest extends Panel implements Runnable { | |
| final static int NOOP = 0; | |
| final static int RED = 1; | |
| final static int GREEN = 2; | |
| final static int BLUE = 3; | |
| final static int ALPHA = 4; | |
| final static int SATURATION = 5; | |
| Thread runner; | |
| DitherControls XControls; | |
| DitherControls YControls; | |
| DitherCanvas canvas; | |
| public DitherTest(GraphicsConfiguration gc) { | |
| String xspec, yspec; | |
| int xvals[] = new int[2]; | |
| int yvals[] = new int[2]; | |
| xspec = "red"; | |
| yspec = "blue"; | |
| int xmethod = colormethod(xspec, xvals); | |
| int ymethod = colormethod(yspec, yvals); | |
| setLayout(new BorderLayout()); | |
| XControls = new DitherControls(this, xvals[0], xvals[1], | |
| xmethod, false); | |
| YControls = new DitherControls(this, yvals[0], yvals[1], | |
| ymethod, true); | |
| YControls.addRenderButton(); | |
| add("North", XControls); | |
| add("South", YControls); | |
| add("Center", canvas = new DitherCanvas(gc)); | |
| } | |
| public void start() { | |
| runner = new Thread(this); | |
| runner.start(); | |
| } | |
| int colormethod(String s, int vals[]) { | |
| int method = NOOP; | |
| if (s == null) { | |
| s = ""; | |
| } | |
| String lower = s.toLowerCase(); | |
| int len = 0; | |
| if (lower.startsWith("red")) { | |
| method = RED; | |
| lower = lower.substring(3); | |
| } else if (lower.startsWith("green")) { | |
| method = GREEN; | |
| lower = lower.substring(5); | |
| } else if (lower.startsWith("blue")) { | |
| method = BLUE; | |
| lower = lower.substring(4); | |
| } else if (lower.startsWith("alpha")) { | |
| method = ALPHA; | |
| lower = lower.substring(4); | |
| } else if (lower.startsWith("saturation")) { | |
| method = SATURATION; | |
| lower = lower.substring(10); | |
| } | |
| if (method == NOOP) { | |
| vals[0] = 0; | |
| vals[1] = 0; | |
| return method; | |
| } | |
| int begval = 0; | |
| int endval = 255; | |
| try { | |
| int dash = lower.indexOf('-'); | |
| if (dash < 0) { | |
| begval = endval = Integer.parseInt(lower); | |
| } else { | |
| begval = Integer.parseInt(lower.substring(0, dash)); | |
| endval = Integer.parseInt(lower.substring(dash + 1)); | |
| } | |
| } catch (Exception e) { | |
| } | |
| if (begval < 0) { | |
| begval = 0; | |
| } | |
| if (endval < 0) { | |
| endval = 0; | |
| } | |
| if (begval > 255) { | |
| begval = 255; | |
| } | |
| if (endval > 255) { | |
| endval = 255; | |
| } | |
| vals[0] = begval; | |
| vals[1] = endval; | |
| return method; | |
| } | |
| void applymethod(int c[], int method, int step, int total, int vals[]) { | |
| if (method == NOOP) | |
| return; | |
| int val = ((total < 2) | |
| ? vals[0] | |
| : vals[0] + ((vals[1] - vals[0]) * step / (total - 1))); | |
| switch (method) { | |
| case RED: | |
| c[0] = val; | |
| break; | |
| case GREEN: | |
| c[1] = val; | |
| break; | |
| case BLUE: | |
| c[2] = val; | |
| break; | |
| case ALPHA: | |
| c[3] = val; | |
| break; | |
| case SATURATION: | |
| int max = Math.max(Math.max(c[0], c[1]), c[2]); | |
| int min = max * (255 - val) / 255; | |
| if (c[0] == 0) { | |
| c[0] = min; | |
| } | |
| if (c[1] == 0) { | |
| c[1] = min; | |
| } | |
| if (c[2] == 0) { | |
| c[2] = min; | |
| } | |
| break; | |
| } | |
| } | |
| public void run() { | |
| canvas.setImage(null); // Wipe previous image | |
| Image img = calculateImage(); | |
| synchronized (this) { | |
| if (img != null && runner == Thread.currentThread()) { | |
| canvas.setImage(img); | |
| } | |
| } | |
| } | |
| /** | |
| * Calculates and returns the image. Halts the calculation and returns | |
| * null if stopped during the calculation. | |
| */ | |
| Image calculateImage() { | |
| Thread me = Thread.currentThread(); | |
| int width = canvas.getSize().width; | |
| int height = canvas.getSize().height; | |
| int xvals[] = new int[2]; | |
| int yvals[] = new int[2]; | |
| int xmethod = XControls.getParams(xvals); | |
| int ymethod = YControls.getParams(yvals); | |
| int pixels[] = new int[width * height]; | |
| int c[] = new int[4]; | |
| int index = 0; | |
| for (int j = 0; j < height; j++) { | |
| for (int i = 0; i < width; i++) { | |
| c[0] = c[1] = c[2] = 0; | |
| c[3] = 255; | |
| if (xmethod < ymethod) { | |
| applymethod(c, xmethod, i, width, xvals); | |
| applymethod(c, ymethod, j, height, yvals); | |
| } else { | |
| applymethod(c, ymethod, j, height, yvals); | |
| applymethod(c, xmethod, i, width, xvals); | |
| } | |
| pixels[index++] = ((c[3] << 24) | | |
| (c[0] << 16) | | |
| (c[1] << 8) | | |
| (c[2] << 0)); | |
| } | |
| // Poll once per row to see if we've been told to stop. | |
| if (runner != me) { | |
| return null; | |
| } | |
| } | |
| return createImage(new MemoryImageSource(width, height, | |
| ColorModel.getRGBdefault(), pixels, 0, width)); | |
| } | |
| public String getInfo() { | |
| return "An interactive demonstration of dithering."; | |
| } | |
| public String[][] getParameterInfo() { | |
| String[][] info = { | |
| {"xaxis", "{RED, GREEN, BLUE, PINK, ORANGE, MAGENTA, CYAN, WHITE, YELLOW, GRAY, DARKGRAY}", | |
| "The color of the Y axis. Default is RED."}, | |
| {"yaxis", "{RED, GREEN, BLUE, PINK, ORANGE, MAGENTA, CYAN, WHITE, YELLOW, GRAY, DARKGRAY}", | |
| "The color of the X axis. Default is BLUE."} | |
| }; | |
| return info; | |
| } | |
| } | |
| class DitherControls extends Panel implements ActionListener { | |
| TextField start; | |
| TextField end; | |
| Button button; | |
| Choice choice; | |
| DitherTest dt; | |
| static LayoutManager dcLayout = new FlowLayout(FlowLayout.CENTER, 10, 5); | |
| public DitherControls(DitherTest app, int s, int e, int type, | |
| boolean vertical) { | |
| dt = app; | |
| setLayout(dcLayout); | |
| add(new Label(vertical ? "Vertical" : "Horizontal")); | |
| add(choice = new Choice()); | |
| choice.addItem("Noop"); | |
| choice.addItem("Red"); | |
| choice.addItem("Green"); | |
| choice.addItem("Blue"); | |
| choice.addItem("Alpha"); | |
| choice.addItem("Saturation"); | |
| choice.select(type); | |
| add(start = new TextField(Integer.toString(s), 4)); | |
| add(end = new TextField(Integer.toString(e), 4)); | |
| } | |
| public void addRenderButton() { | |
| add(button = new Button("New Image")); | |
| button.addActionListener(this); | |
| } | |
| public int getParams(int vals[]) { | |
| vals[0] = Integer.parseInt(start.getText()); | |
| vals[1] = Integer.parseInt(end.getText()); | |
| return choice.getSelectedIndex(); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| if (e.getSource() == button) { | |
| dt.start(); | |
| } | |
| } | |
| } |