1
+ /*
2
+ * Copyright (c) 2023, 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
+ import java .awt .Image ;
25
+ import java .awt .image .BufferedImage ;
26
+ import java .awt .image .ImageObserver ;
27
+
28
+ /**
29
+ * @test
30
+ * @bug 4200096
31
+ * @summary this real-world example detaches an ImageConsumer from an OSIS immediately after it learns the dimensions.
32
+ * @author Jeremy Wood
33
+ */
34
+
35
+ /**
36
+ * This adds an ImageObserver that is only interested in identifying the dimensions of an ImageProducer.
37
+ * <p>
38
+ * Once it has the dimensions: {@link java.awt.image.ImageObserver#imageUpdate(Image, int, int, int, int, int)}
39
+ * returns false. This triggers the caller to remove the ImageObserver for us. And removing an ImageObserver
40
+ * while an OffScreenImageSource is mid-production triggers the NPE that is JDK-4200096.
41
+ * <p>
42
+ * The expected behavior is for this method to complete without OffScreenImageSource throwing/catching a NPE.
43
+ * <p>
44
+ * What's interesting about this test is: we never even explicitly call {@link java.awt.image.ImageProducer#addConsumer(ImageConsumer)}
45
+ * or {@link java.awt.image.ImageProducer#removeConsumer(ImageConsumer)} (ImageConsumer)}.
46
+ * </p>
47
+ */
48
+ public class ImageSizeTest {
49
+ public static void main (String [] args ) throws Exception {
50
+ try (AutoCloseable setup = bug4200096 .setupTest (false )) {
51
+ Image img = createAbstractImage ();
52
+ ImageObserver observer = new ImageObserver () {
53
+ Integer imageWidth , imageHeight ;
54
+ @ Override
55
+ public boolean imageUpdate (Image img , int infoflags , int x , int y , int width , int height ) {
56
+ if ( (infoflags | ImageObserver .WIDTH ) > 0 ) {
57
+ imageWidth = width ;
58
+ }
59
+ if ( (infoflags | ImageObserver .HEIGHT ) > 0 ) {
60
+ imageHeight = height ;
61
+ }
62
+
63
+ if (imageWidth != null || imageHeight != null )
64
+ return false ;
65
+ return true ;
66
+
67
+ }
68
+ };
69
+ img .getWidth (observer );
70
+ }
71
+ }
72
+
73
+ /**
74
+ * This creates a ToolkitImage, so it is not a BufferedImage.
75
+ * <p>
76
+ * This specific implementation happens to rely on scaling an existing
77
+ * BufferedImage, because that seemed like an easy way to avoid bundling a
78
+ * JPG/PNG with this unit test. But this return value still happens to be
79
+ * a ToolkitImage, which is what a JPG/PNG would also be (when loaded
80
+ * via the Toolkit class and not ImageIO).
81
+ * </p>
82
+ */
83
+ private static Image createAbstractImage () {
84
+ BufferedImage bufferedImage = new BufferedImage (1 , 1 , BufferedImage .TYPE_INT_ARGB );
85
+ Image img = bufferedImage .getScaledInstance (2 , 2 , Image .SCALE_SMOOTH );
86
+ return img ;
87
+ }
88
+ }
0 commit comments