1 /* 2 * Copyright (c) 2003, 2007, 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.awt.Color; 29 import java.awt.GraphicsEnvironment; 30 import java.awt.GraphicsConfiguration; 31 import java.awt.Image; 32 import java.awt.ImageCapabilities; 33 import java.awt.image.BufferedImage; 34 import java.util.concurrent.ConcurrentHashMap; 35 import java.util.Iterator; 36 import sun.java2d.SurfaceData; 37 import sun.java2d.SurfaceDataProxy; 38 import sun.java2d.loops.CompositeType; 39 40 /** 41 * The abstract base class that manages the various SurfaceData objects that 42 * represent an Image's contents. Subclasses can customize how the surfaces 43 * are organized, whether to cache the original contents in an accelerated 44 * surface, and so on. 45 * <p> 46 * The SurfaceManager also maintains an arbitrary "cache" mechanism which 47 * allows other agents to store data in it specific to their use of this 48 * image. The most common use of the caching mechanism is for destination 49 * SurfaceData objects to store cached copies of the source image. 50 */ 51 public abstract class SurfaceManager { 52 53 public static abstract class ImageAccessor { 54 public abstract SurfaceManager getSurfaceManager(Image img); 55 public abstract void setSurfaceManager(Image img, SurfaceManager mgr); 56 } 57 58 private static ImageAccessor imgaccessor; 59 60 public static void setImageAccessor(ImageAccessor ia) { 61 if (imgaccessor != null) { 62 throw new InternalError("Attempt to set ImageAccessor twice"); 63 } 64 imgaccessor = ia; 65 } 66 67 /** 68 * Returns the SurfaceManager object contained within the given Image. 69 */ 70 public static SurfaceManager getManager(Image img) { 71 SurfaceManager sMgr = imgaccessor.getSurfaceManager(img); 72 if (sMgr == null) { 73 /* 74 * In practice only a BufferedImage will get here. 75 */ 76 try { 77 BufferedImage bi = (BufferedImage) img; 78 sMgr = new BufImgSurfaceManager(bi); 79 setManager(bi, sMgr); 80 } catch (ClassCastException e) { 81 throw new IllegalArgumentException("Invalid Image variant"); 82 } 83 } 84 return sMgr; 85 } 86 87 public static void setManager(Image img, SurfaceManager mgr) { 88 imgaccessor.setSurfaceManager(img, mgr); 89 } 90 91 private ConcurrentHashMap<Object,Object> cacheMap; 92 93 /** 94 * Return an arbitrary cached object for an arbitrary cache key. 95 * Other objects can use this mechanism to store cached data about 96 * the source image that will let them save time when using or 97 * manipulating the image in the future. 98 * <p> 99 * Note that the cache is maintained as a simple Map with no 100 * attempts to keep it up to date or invalidate it so any data 101 * stored here must either not be dependent on the state of the 102 * image or it must be individually tracked to see if it is 103 * outdated or obsolete. 104 * <p> 105 * The SurfaceData object of the primary (destination) surface 106 * has a StateTracker mechanism which can help track the validity 107 * and "currentness" of any data stored here. 108 * For convenience and expediency an object stored as cached 109 * data may implement the FlushableCacheData interface specified 110 * below so that it may be notified immediately if the flush() 111 * method is ever called. 112 */ 113 public Object getCacheData(Object key) { 114 return (cacheMap == null) ? null : cacheMap.get(key); 115 } 116 117 /** 118 * Store an arbitrary cached object for an arbitrary cache key. 119 * See the getCacheData() method for notes on tracking the 120 * validity of data stored using this mechanism. 121 */ 122 public void setCacheData(Object key, Object value) { 123 if (cacheMap == null) { 124 synchronized (this) { 125 if (cacheMap == null) { 126 cacheMap = new ConcurrentHashMap<>(2); 127 } 128 } 129 } 130 cacheMap.put(key, value); 131 } 132 133 /** 134 * Returns the main SurfaceData object that "owns" the pixels for 135 * this SurfaceManager. This SurfaceData is used as the destination 136 * surface in a rendering operation and is the most authoritative 137 * storage for the current state of the pixels, though other 138 * versions might be cached in other locations for efficiency. 139 */ 140 public abstract SurfaceData getPrimarySurfaceData(); 141 142 /** 143 * Restores the primary surface being managed, and then returns the 144 * replacement surface. This is called when an accelerated surface has 145 * been "lost", in an attempt to auto-restore its contents. 146 */ 147 public abstract SurfaceData restoreContents(); 148 149 /** 150 * Notification that any accelerated surfaces associated with this manager 151 * have been "lost", which might mean that they need to be manually 152 * restored or recreated. 153 * 154 * The default implementation does nothing, but platform-specific 155 * variants which have accelerated surfaces should perform any necessary 156 * actions. 157 */ 158 public void acceleratedSurfaceLost() {} 159 160 /** 161 * Returns an ImageCapabilities object which can be 162 * inquired as to the specific capabilities of this 163 * Image. The capabilities object will return true for 164 * isAccelerated() if the image has a current and valid 165 * SurfaceDataProxy object cached for the specified 166 * GraphicsConfiguration parameter. 167 * <p> 168 * This class provides a default implementation of the 169 * ImageCapabilities that will try to determine if there 170 * is an associated SurfaceDataProxy object and if it is 171 * up to date, but only works for GraphicsConfiguration 172 * objects which implement the ProxiedGraphicsConfig 173 * interface defined below. In practice, all configs 174 * which can be accelerated are currently implementing 175 * that interface. 176 * <p> 177 * A null GraphicsConfiguration returns a value based on whether the 178 * image is currently accelerated on its default GraphicsConfiguration. 179 * 180 * @see java.awt.Image#getCapabilities 181 * @since 1.5 182 */ 183 public ImageCapabilities getCapabilities(GraphicsConfiguration gc) { 184 return new ImageCapabilitiesGc(gc); 185 } 186 187 class ImageCapabilitiesGc extends ImageCapabilities { 188 GraphicsConfiguration gc; 189 190 public ImageCapabilitiesGc(GraphicsConfiguration gc) { 191 super(false); 192 this.gc = gc; 193 } 194 195 public boolean isAccelerated() { 196 // Note that when img.getAccelerationPriority() gets set to 0 197 // we remove SurfaceDataProxy objects from the cache and the 198 // answer will be false. 199 GraphicsConfiguration tmpGc = gc; 200 if (tmpGc == null) { 201 tmpGc = GraphicsEnvironment.getLocalGraphicsEnvironment(). 202 getDefaultScreenDevice().getDefaultConfiguration(); 203 } 204 if (tmpGc instanceof ProxiedGraphicsConfig) { 205 Object proxyKey = 206 ((ProxiedGraphicsConfig) tmpGc).getProxyKey(); 207 if (proxyKey != null) { 208 SurfaceDataProxy sdp = 209 (SurfaceDataProxy) getCacheData(proxyKey); 210 return (sdp != null && sdp.isAccelerated()); 211 } 212 } 213 return false; 214 } 215 } 216 217 /** 218 * An interface for GraphicsConfiguration objects to implement if 219 * their surfaces accelerate images using SurfaceDataProxy objects. 220 * 221 * Implementing this interface facilitates the default 222 * implementation of getImageCapabilities() above. 223 */ 224 public static interface ProxiedGraphicsConfig { 225 /** 226 * Return the key that destination surfaces created on the 227 * given GraphicsConfiguration use to store SurfaceDataProxy 228 * objects for their cached copies. 229 */ 230 public Object getProxyKey(); 231 } 232 233 /** 234 * Releases system resources in use by ancillary SurfaceData objects, 235 * such as surfaces cached in accelerated memory. Subclasses should 236 * override to release any of their flushable data. 237 * <p> 238 * The default implementation will visit all of the value objects 239 * in the cacheMap and flush them if they implement the 240 * FlushableCacheData interface. 241 */ 242 public synchronized void flush() { 243 flush(false); 244 } 245 246 synchronized void flush(boolean deaccelerate) { 247 if (cacheMap != null) { 248 Iterator<Object> i = cacheMap.values().iterator(); 249 while (i.hasNext()) { 250 Object o = i.next(); 251 if (o instanceof FlushableCacheData) { 252 if (((FlushableCacheData) o).flush(deaccelerate)) { 253 i.remove(); 254 } 255 } 256 } 257 } 258 } 259 260 /** 261 * An interface for Objects used in the SurfaceManager cache 262 * to implement if they have data that should be flushed when 263 * the Image is flushed. 264 */ 265 public static interface FlushableCacheData { 266 /** 267 * Flush all cached resources. 268 * The deaccelerated parameter indicates if the flush is 269 * happening because the associated surface is no longer 270 * being accelerated (for instance the acceleration priority 271 * is set below the threshold needed for acceleration). 272 * Returns a boolean that indicates if the cached object is 273 * no longer needed and should be removed from the cache. 274 */ 275 public boolean flush(boolean deaccelerated); 276 } 277 278 /** 279 * Called when image's acceleration priority is changed. 280 * <p> 281 * The default implementation will visit all of the value objects 282 * in the cacheMap when the priority gets set to 0.0 and flush them 283 * if they implement the FlushableCacheData interface. 284 */ 285 public void setAccelerationPriority(float priority) { 286 if (priority == 0.0f) { 287 flush(true); 288 } 289 } 290 }