1 /* 2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 7124347 27 * @summary Verifies that rendering with XOR composite, and arbitraty 28 * custom composite doesn not cause internal errors. 29 * 30 * @run main/othervm -Dsun.java2d.opengl=True CustomCompositeTest 31 */ 32 33 import java.awt.AWTException; 34 import java.awt.Color; 35 import java.awt.Composite; 36 import java.awt.CompositeContext; 37 import java.awt.Dimension; 38 import java.awt.GradientPaint; 39 import java.awt.Graphics; 40 import java.awt.Graphics2D; 41 import java.awt.GraphicsConfiguration; 42 import java.awt.GraphicsEnvironment; 43 import java.awt.ImageCapabilities; 44 import java.awt.RenderingHints; 45 import java.awt.image.BufferedImage; 46 import java.awt.image.ColorModel; 47 import java.awt.image.DataBufferInt; 48 import java.awt.image.Raster; 49 import java.awt.image.SinglePixelPackedSampleModel; 50 import java.awt.image.VolatileImage; 51 import java.awt.image.WritableRaster; 52 import java.util.concurrent.CountDownLatch; 53 import javax.swing.JComponent; 54 import javax.swing.JFrame; 55 import javax.swing.SwingUtilities; 56 57 public class CustomCompositeTest { 58 59 private static JFrame frame; 60 private static CountDownLatch paintLatch; 61 private static Throwable paintError; 62 63 public static void main(String[] args) { 64 65 paintLatch = new CountDownLatch(1); 66 paintError = null; 67 68 SwingUtilities.invokeLater(new Runnable() { 69 public void run() { 70 initGUI(); 71 } 72 }); 73 74 try { 75 paintLatch.await(); 76 } catch (InterruptedException e) { 77 }; 78 System.out.println("Paint is done!"); 79 if (paintError != null) { 80 frame.dispose(); 81 throw new RuntimeException("Test FAILED.", paintError); 82 } 83 84 System.out.println("Phase 1: PASSED."); 85 86 // now resise the frame in order to cause re-paint with accelerated 87 // source images. 88 paintError = null; 89 paintLatch = new CountDownLatch(1); 90 91 SwingUtilities.invokeLater(new Runnable() { 92 @Override 93 public void run() { 94 Dimension size = frame.getSize(); 95 size.width += 50; 96 size.height += 50; 97 98 frame.setSize(size); 99 } 100 }); 101 102 try { 103 paintLatch.await(); 104 } catch (InterruptedException e) { 105 }; 106 if (paintError != null) { 107 frame.dispose(); 108 throw new RuntimeException("Resize test FAILED.", paintError); 109 } 110 frame.dispose(); 111 System.out.println("Phase 2: PASSED."); 112 113 GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); 114 GraphicsConfiguration cfg = env.getDefaultScreenDevice().getDefaultConfiguration(); 115 // test rendering to accelerated volatile image 116 testVolatileImage(cfg, true); 117 System.out.println("Phase 3: PASSED."); 118 119 // test rendering to unaccelerated volatile image 120 testVolatileImage(cfg, false); 121 System.out.println("Phase 4: PASSED."); 122 } 123 124 private static void testVolatileImage(GraphicsConfiguration cfg, 125 boolean accelerated) 126 { 127 VolatileImage dst = null; 128 try { 129 dst = cfg.createCompatibleVolatileImage(640, 480, 130 new ImageCapabilities(accelerated)); 131 } catch (AWTException e) { 132 System.out.println("Unable to create volatile image, skip the test."); 133 return; 134 } 135 renderToVolatileImage(dst); 136 } 137 138 private static void renderToVolatileImage(VolatileImage dst) { 139 Graphics2D g = dst.createGraphics(); 140 do { 141 System.out.println("Render to volatile image.."); 142 try { 143 MyComp.renderTest(g, dst.getHeight(), dst.getHeight()); 144 } catch (Throwable e) { 145 throw new RuntimeException("Test FAILED.", e); 146 } 147 } while (dst.contentsLost()); 148 System.out.println("Done."); 149 } 150 151 private static void initGUI() { 152 frame = new JFrame("Silly composite"); 153 frame.getContentPane().add(new MyComp()); 154 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 155 frame.pack(); 156 frame.setVisible(true); 157 } 158 159 private static class MyComp extends JComponent { 160 161 private static BufferedImage theImage; 162 163 public MyComp() { 164 } 165 166 private static BufferedImage getTestImage() { 167 if (theImage == null) { 168 theImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB); 169 Graphics2D g2d = theImage.createGraphics(); 170 g2d.setColor(Color.red); 171 g2d.fillRect(0, 0, 256, 256); 172 173 g2d.setPaint(new GradientPaint(0, 0, Color.red, 256, 256, Color.blue)); 174 g2d.fillRect(0, 100, 256, 256); 175 g2d.dispose(); 176 } 177 return theImage; 178 } 179 180 public Dimension getPreferredSize() { 181 return new Dimension(640, 375); 182 } 183 184 public void paintComponent(Graphics g) { 185 186 187 Graphics2D g2d = (Graphics2D) g; 188 try { 189 renderTest(g2d, getWidth(), getHeight()); 190 } catch (Throwable e) { 191 paintError = e; 192 } 193 if (paintLatch != null) { 194 paintLatch.countDown(); 195 } 196 } 197 198 public static void renderTest(Graphics2D g2d, int w, int h) { 199 g2d.setColor(Color.yellow); 200 g2d.fillRect(0, 0, w, h); 201 202 BufferedImage image = getTestImage(); 203 // draw original image 204 g2d.drawRenderedImage(image, null); 205 206 // draw image with custom composite 207 g2d.translate(175, 25); 208 Composite currentComposite = g2d.getComposite(); 209 g2d.setComposite(new TestComposite()); 210 g2d.drawRenderedImage(image, null); 211 g2d.setComposite(currentComposite); 212 213 // draw image with XOR 214 g2d.translate(175, 25); 215 g2d.setXORMode(Color.red); 216 g2d.drawRenderedImage(image, null); 217 218 219 System.out.println("Painting is done..."); 220 } 221 } 222 223 // A silly custom Composite to demonstrate the problem - just inverts the RGB 224 private static class TestComposite implements Composite { 225 226 public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) { 227 return new TestCompositeContext(); 228 } 229 } 230 231 private static class TestCompositeContext implements CompositeContext { 232 233 public void dispose() { 234 } 235 236 public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { 237 int w = src.getWidth(); 238 int h = src.getHeight(); 239 240 DataBufferInt srcDB = (DataBufferInt) src.getDataBuffer(); 241 DataBufferInt dstOutDB = (DataBufferInt) dstOut.getDataBuffer(); 242 int srcRGB[] = srcDB.getBankData()[0]; 243 int dstOutRGB[] = dstOutDB.getBankData()[0]; 244 int srcOffset = srcDB.getOffset(); 245 int dstOutOffset = dstOutDB.getOffset(); 246 int srcScanStride = ((SinglePixelPackedSampleModel) src.getSampleModel()).getScanlineStride(); 247 int dstOutScanStride = ((SinglePixelPackedSampleModel) dstOut.getSampleModel()).getScanlineStride(); 248 int srcAdjust = srcScanStride - w; 249 int dstOutAdjust = dstOutScanStride - w; 250 251 int si = srcOffset; 252 int doi = dstOutOffset; 253 254 for (int i = 0; i < h; i++) { 255 for (int j = 0; j < w; j++) { 256 dstOutRGB[doi] = srcRGB[si] ^ 0x00ffffff; 257 si++; 258 doi++; 259 } 260 261 si += srcAdjust; 262 doi += dstOutAdjust; 263 } 264 } 265 } 266 }