1 /* 2 * Copyright (c) 2012, 2016, 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 * @key headful 27 * @bug 7124347 28 * @summary Verifies that rendering with XOR composite, and arbitraty 29 * custom composite doesn not cause internal errors. 30 * 31 * @run main/othervm -Dsun.java2d.opengl=True CustomCompositeTest 32 */ 33 34 import java.awt.AWTException; 35 import java.awt.Color; 36 import java.awt.Composite; 37 import java.awt.CompositeContext; 38 import java.awt.Dimension; 39 import java.awt.GradientPaint; 40 import java.awt.Graphics; 41 import java.awt.Graphics2D; 42 import java.awt.GraphicsConfiguration; 43 import java.awt.GraphicsEnvironment; 44 import java.awt.ImageCapabilities; 45 import java.awt.RenderingHints; 46 import java.awt.image.BufferedImage; 47 import java.awt.image.ColorModel; 48 import java.awt.image.DataBufferInt; 49 import java.awt.image.Raster; 50 import java.awt.image.SinglePixelPackedSampleModel; 51 import java.awt.image.VolatileImage; 52 import java.awt.image.WritableRaster; 53 import java.util.concurrent.CountDownLatch; 54 import javax.swing.JComponent; 55 import javax.swing.JFrame; 56 import javax.swing.SwingUtilities; 57 58 public class CustomCompositeTest { 59 60 private static JFrame frame; 61 private static CountDownLatch paintLatch; 62 private static Throwable paintError; 63 64 public static void main(String[] args) { 65 66 paintLatch = new CountDownLatch(1); 67 paintError = null; 68 69 SwingUtilities.invokeLater(new Runnable() { 70 public void run() { 71 initGUI(); 72 } 73 }); 74 75 try { 76 paintLatch.await(); 77 } catch (InterruptedException e) { 78 }; 79 System.out.println("Paint is done!"); 80 if (paintError != null) { 81 frame.dispose(); 82 throw new RuntimeException("Test FAILED.", paintError); 83 } 84 85 System.out.println("Phase 1: PASSED."); 86 87 // now resise the frame in order to cause re-paint with accelerated 88 // source images. 89 paintError = null; 90 paintLatch = new CountDownLatch(1); 91 92 SwingUtilities.invokeLater(new Runnable() { 93 @Override 94 public void run() { 95 Dimension size = frame.getSize(); 96 size.width += 50; 97 size.height += 50; 98 99 frame.setSize(size); 100 } 101 }); 102 103 try { 104 paintLatch.await(); 105 } catch (InterruptedException e) { 106 }; 107 if (paintError != null) { 108 frame.dispose(); 109 throw new RuntimeException("Resize test FAILED.", paintError); 110 } 111 frame.dispose(); 112 System.out.println("Phase 2: PASSED."); 113 114 GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); 115 GraphicsConfiguration cfg = env.getDefaultScreenDevice().getDefaultConfiguration(); 116 // test rendering to accelerated volatile image 117 testVolatileImage(cfg, true); 118 System.out.println("Phase 3: PASSED."); 119 120 // test rendering to unaccelerated volatile image 121 testVolatileImage(cfg, false); 122 System.out.println("Phase 4: PASSED."); 123 } 124 125 private static void testVolatileImage(GraphicsConfiguration cfg, 126 boolean accelerated) 127 { 128 VolatileImage dst = null; 129 try { 130 dst = cfg.createCompatibleVolatileImage(640, 480, 131 new ImageCapabilities(accelerated)); 132 } catch (AWTException e) { 133 System.out.println("Unable to create volatile image, skip the test."); 134 return; 135 } 136 renderToVolatileImage(dst); 137 } 138 139 private static void renderToVolatileImage(VolatileImage dst) { 140 Graphics2D g = dst.createGraphics(); 141 do { 142 System.out.println("Render to volatile image.."); 143 try { 144 MyComp.renderTest(g, dst.getHeight(), dst.getHeight()); 145 } catch (Throwable e) { 146 throw new RuntimeException("Test FAILED.", e); 147 } 148 } while (dst.contentsLost()); 149 System.out.println("Done."); 150 } 151 152 private static void initGUI() { 153 frame = new JFrame("Silly composite"); 154 frame.getContentPane().add(new MyComp()); 155 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 156 frame.pack(); 157 frame.setVisible(true); 158 } 159 160 private static class MyComp extends JComponent { 161 162 private static BufferedImage theImage; 163 164 public MyComp() { 165 } 166 167 private static BufferedImage getTestImage() { 168 if (theImage == null) { 169 theImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB); 170 Graphics2D g2d = theImage.createGraphics(); 171 g2d.setColor(Color.red); 172 g2d.fillRect(0, 0, 256, 256); 173 174 g2d.setPaint(new GradientPaint(0, 0, Color.red, 256, 256, Color.blue)); 175 g2d.fillRect(0, 100, 256, 256); 176 g2d.dispose(); 177 } 178 return theImage; 179 } 180 181 public Dimension getPreferredSize() { 182 return new Dimension(640, 375); 183 } 184 185 public void paintComponent(Graphics g) { 186 187 188 Graphics2D g2d = (Graphics2D) g; 189 try { 190 renderTest(g2d, getWidth(), getHeight()); 191 } catch (Throwable e) { 192 paintError = e; 193 } 194 if (paintLatch != null) { 195 paintLatch.countDown(); 196 } 197 } 198 199 public static void renderTest(Graphics2D g2d, int w, int h) { 200 g2d.setColor(Color.yellow); 201 g2d.fillRect(0, 0, w, h); 202 203 BufferedImage image = getTestImage(); 204 // draw original image 205 g2d.drawRenderedImage(image, null); 206 207 // draw image with custom composite 208 g2d.translate(175, 25); 209 Composite currentComposite = g2d.getComposite(); 210 g2d.setComposite(new TestComposite()); 211 g2d.drawRenderedImage(image, null); 212 g2d.setComposite(currentComposite); 213 214 // draw image with XOR 215 g2d.translate(175, 25); 216 g2d.setXORMode(Color.red); 217 g2d.drawRenderedImage(image, null); 218 219 220 System.out.println("Painting is done..."); 221 } 222 } 223 224 // A silly custom Composite to demonstrate the problem - just inverts the RGB 225 private static class TestComposite implements Composite { 226 227 public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) { 228 return new TestCompositeContext(); 229 } 230 } 231 232 private static class TestCompositeContext implements CompositeContext { 233 234 public void dispose() { 235 } 236 237 public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { 238 int w = src.getWidth(); 239 int h = src.getHeight(); 240 241 DataBufferInt srcDB = (DataBufferInt) src.getDataBuffer(); 242 DataBufferInt dstOutDB = (DataBufferInt) dstOut.getDataBuffer(); 243 int srcRGB[] = srcDB.getBankData()[0]; 244 int dstOutRGB[] = dstOutDB.getBankData()[0]; 245 int srcOffset = srcDB.getOffset(); 246 int dstOutOffset = dstOutDB.getOffset(); 247 int srcScanStride = ((SinglePixelPackedSampleModel) src.getSampleModel()).getScanlineStride(); 248 int dstOutScanStride = ((SinglePixelPackedSampleModel) dstOut.getSampleModel()).getScanlineStride(); 249 int srcAdjust = srcScanStride - w; 250 int dstOutAdjust = dstOutScanStride - w; 251 252 int si = srcOffset; 253 int doi = dstOutOffset; 254 255 for (int i = 0; i < h; i++) { 256 for (int j = 0; j < w; j++) { 257 dstOutRGB[doi] = srcRGB[si] ^ 0x00ffffff; 258 si++; 259 doi++; 260 } 261 262 si += srcAdjust; 263 doi += dstOutAdjust; 264 } 265 } 266 } 267 }