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.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.awt.image.VolatileImage;
  35 import java.util.concurrent.ConcurrentHashMap;
  36 import java.util.Iterator;
  37 import sun.java2d.SurfaceData;
  38 import sun.java2d.SurfaceDataProxy;
  39 import sun.java2d.loops.CompositeType;
  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 static abstract class ImageAccessor {
  55         public abstract SurfaceManager getSurfaceManager(Image img);
  56         public abstract void setSurfaceManager(Image img, SurfaceManager mgr);
  57     }
  58 
  59     private static ImageAccessor imgaccessor;
  60 
  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      */
  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 IllegalArgumentException("Invalid Image variant");
  83             }
  84         }
  85         return sMgr;
  86     }
  87 
  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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 184     public ImageCapabilities getCapabilities(GraphicsConfiguration gc) {
 185         return new ImageCapabilitiesGc(gc);
 186     }
 187 
 188     class ImageCapabilitiesGc extends ImageCapabilities {
 189         GraphicsConfiguration gc;
 190 
 191         public ImageCapabilitiesGc(GraphicsConfiguration gc) {
 192             super(false);
 193             this.gc = gc;
 194         }
 195 
 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          */
 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      */
 243     public synchronized void flush() {
 244         flush(false);
 245     }
 246 
 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          */
 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      */
 286     public void setAccelerationPriority(float priority) {
 287         if (priority == 0.0f) {
 288             flush(true);
 289         }
 290     }
 291 
 292     /**
 293      * Returns a scale factor of the image. This is utility method, which
 294      * fetches information from the SurfaceData of the image.
 295      *
 296      * @see SurfaceData#getDefaultScale
 297      */
 298     public static int getImageScale(final Image img) {
 299         if (!(img instanceof VolatileImage)) {
 300             return 1;
 301         }
 302         final SurfaceManager sm = getManager(img);
 303         return sm.getPrimarySurfaceData().getDefaultScale();
 304     }
 305 }