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