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