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