1 /*
2  * Copyright (c) 1995, 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.awt.image;
27 
28 import java.lang.ref.WeakReference;
29 import java.awt.Image;
30 import java.awt.image.ImageObserver;
31 
32 import java.security.AccessControlContext;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 
36 public abstract class ImageWatched {
37     public static Link endlink = new Link();
38 
39     public Link watcherList;
40 
ImageWatched()41     public ImageWatched() {
42         watcherList = endlink;
43     }
44 
45     /*
46      * This class defines a node on a linked list of ImageObservers.
47      * The base class defines the dummy implementation used for the
48      * last link on all chains and a subsequent subclass then
49      * defines the standard implementation that manages a weak
50      * reference to a real ImageObserver.
51      */
52     public static class Link {
53         /*
54          * Check if iw is the referent of this Link or any
55          * subsequent Link objects on this chain.
56          */
isWatcher(ImageObserver iw)57         public boolean isWatcher(ImageObserver iw) {
58             return false;  // No "iw" down here.
59         }
60 
61         /*
62          * Remove this Link from the chain if its referent
63          * is the indicated target or if it has been nulled
64          * out by the garbage collector.
65          * Return the new remainder of the chain.
66          * The argument may be null which will trigger
67          * the chain to remove only the dead (null) links.
68          * This method is only ever called inside a
69          * synchronized block so Link.next modifications
70          * will be safe.
71          */
removeWatcher(ImageObserver iw)72         public Link removeWatcher(ImageObserver iw) {
73             return this;  // Leave me as the end link.
74         }
75 
76         /*
77          * Deliver the indicated image update information
78          * to the referent of this Link and return a boolean
79          * indicating whether or not some referent became
80          * null or has indicated a lack of interest in
81          * further updates to its imageUpdate() method.
82          * This method is not called inside a synchronized
83          * block so Link.next modifications are not safe.
84          */
newInfo(Image img, int info, int x, int y, int w, int h)85         public boolean newInfo(Image img, int info,
86                                int x, int y, int w, int h)
87         {
88             return false;  // No disinterested parties down here.
89         }
90     }
91 
92     static class AccWeakReference<T> extends WeakReference<T> {
93 
94          private final AccessControlContext acc;
95 
AccWeakReference(T ref)96          AccWeakReference(T ref) {
97              super(ref);
98              acc = AccessController.getContext();
99          }
100     }
101 
102     /*
103      * Standard Link implementation to manage a Weak Reference
104      * to an ImageObserver.
105      */
106     public static class WeakLink extends Link {
107         private final AccWeakReference<ImageObserver> myref;
108         private Link next;
109 
WeakLink(ImageObserver obs, Link next)110         public WeakLink(ImageObserver obs, Link next) {
111             myref = new AccWeakReference<ImageObserver>(obs);
112             this.next = next;
113         }
114 
isWatcher(ImageObserver iw)115         public boolean isWatcher(ImageObserver iw) {
116             return (myref.get() == iw || next.isWatcher(iw));
117         }
118 
removeWatcher(ImageObserver iw)119         public Link removeWatcher(ImageObserver iw) {
120             ImageObserver myiw = myref.get();
121             if (myiw == null) {
122                 // Remove me from the chain, but continue recursion.
123                 return next.removeWatcher(iw);
124             }
125             // At this point myiw is not null so we know this test will
126             // never succeed if this is a pruning pass (iw == null).
127             if (myiw == iw) {
128                 // Remove me from the chain and end the recursion here.
129                 return next;
130             }
131             // I am alive, but not the one to be removed, recurse
132             // and update my next link and leave me in the chain.
133             next = next.removeWatcher(iw);
134             return this;
135         }
136 
update(ImageObserver iw, AccessControlContext acc, Image img, int info, int x, int y, int w, int h)137         private static boolean update(ImageObserver iw, AccessControlContext acc,
138                                       Image img, int info,
139                                       int x, int y, int w, int h) {
140 
141             if (acc != null || System.getSecurityManager() != null) {
142                 return AccessController.doPrivileged(
143                        (PrivilegedAction<Boolean>) () -> {
144                             return iw.imageUpdate(img, info, x, y, w, h);
145                       }, acc);
146             }
147             return false;
148         }
149 
newInfo(Image img, int info, int x, int y, int w, int h)150         public boolean newInfo(Image img, int info,
151                                int x, int y, int w, int h)
152         {
153             // Note tail recursion because items are added LIFO.
154             boolean ret = next.newInfo(img, info, x, y, w, h);
155             ImageObserver myiw = myref.get();
156             if (myiw == null) {
157                 // My referent is null so we must prune in a second pass.
158                 ret = true;
159             } else if (update(myiw, myref.acc, img, info, x, y, w, h) == false) {
160                 // My referent has lost interest so clear it and ask
161                 // for a pruning pass to remove it later.
162                 myref.clear();
163                 ret = true;
164             }
165             return ret;
166         }
167     }
168 
addWatcher(ImageObserver iw)169     public synchronized void addWatcher(ImageObserver iw) {
170         if (iw != null && !isWatcher(iw)) {
171             watcherList = new WeakLink(iw, watcherList);
172         }
173         watcherList = watcherList.removeWatcher(null);
174     }
175 
isWatcher(ImageObserver iw)176     public synchronized boolean isWatcher(ImageObserver iw) {
177         return watcherList.isWatcher(iw);
178     }
179 
removeWatcher(ImageObserver iw)180     public void removeWatcher(ImageObserver iw) {
181         synchronized (this) {
182             watcherList = watcherList.removeWatcher(iw);
183         }
184         if (watcherList == endlink) {
185             notifyWatcherListEmpty();
186         }
187     }
188 
isWatcherListEmpty()189     public boolean isWatcherListEmpty() {
190         synchronized (this) {
191             watcherList = watcherList.removeWatcher(null);
192         }
193         return (watcherList == endlink);
194     }
195 
newInfo(Image img, int info, int x, int y, int w, int h)196     public void newInfo(Image img, int info, int x, int y, int w, int h) {
197         if (watcherList.newInfo(img, info, x, y, w, h)) {
198             // Some Link returned true so we now need to prune dead links.
199             removeWatcher(null);
200         }
201     }
202 
notifyWatcherListEmpty()203     protected abstract void notifyWatcherListEmpty();
204 }
205