1 /*
2  * Copyright (c) 2012, 2018, 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 8198613
28  * @summary Verifies that rendering with XOR composite, and arbitraty
29  *          custom composite doesn not cause internal errors.
30  *
31  * @run     main/othervm 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 
main(String[] args)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 
testVolatileImage(GraphicsConfiguration cfg, boolean accelerated)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 
renderToVolatileImage(VolatileImage dst)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 
initGUI()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 
MyComp()164         public MyComp() {
165         }
166 
getTestImage()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 
getPreferredSize()181         public Dimension getPreferredSize() {
182             return new Dimension(640, 375);
183         }
184 
paintComponent(Graphics g)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 
renderTest(Graphics2D g2d, int w, int h)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 
createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints)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 
dispose()234         public void dispose() {
235         }
236 
compose(Raster src, Raster dstIn, WritableRaster dstOut)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 }
268