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 }