/* | 
|
 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code is distributed in the hope that it will be useful, but WITHOUT | 
|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package sun.awt.image;  | 
|
import java.awt.Color;  | 
|
import java.awt.GraphicsEnvironment;  | 
|
import java.awt.GraphicsConfiguration;  | 
|
import java.awt.Image;  | 
|
import java.awt.ImageCapabilities;  | 
|
import java.awt.image.BufferedImage;  | 
|
import java.awt.image.VolatileImage;  | 
|
import java.util.concurrent.ConcurrentHashMap;  | 
|
import java.util.Iterator;  | 
|
import sun.java2d.SurfaceData;  | 
|
import sun.java2d.SurfaceDataProxy;  | 
|
import sun.java2d.loops.CompositeType;  | 
|
/** | 
|
 * The abstract base class that manages the various SurfaceData objects that | 
|
 * represent an Image's contents.  Subclasses can customize how the surfaces | 
|
 * are organized, whether to cache the original contents in an accelerated | 
|
 * surface, and so on. | 
|
 * <p> | 
|
 * The SurfaceManager also maintains an arbitrary "cache" mechanism which | 
|
 * allows other agents to store data in it specific to their use of this | 
|
 * image.  The most common use of the caching mechanism is for destination | 
|
 * SurfaceData objects to store cached copies of the source image. | 
|
*/  | 
|
public abstract class SurfaceManager { | 
|
    public static abstract class ImageAccessor { | 
|
public abstract SurfaceManager getSurfaceManager(Image img);  | 
|
public abstract void setSurfaceManager(Image img, SurfaceManager mgr);  | 
|
}  | 
|
private static ImageAccessor imgaccessor;  | 
|
    public static void setImageAccessor(ImageAccessor ia) { | 
|
if (imgaccessor != null) {  | 
|
throw new InternalError("Attempt to set ImageAccessor twice");  | 
|
}  | 
|
imgaccessor = ia;  | 
|
}  | 
|
    /** | 
|
     * Returns the SurfaceManager object contained within the given Image. | 
|
*/  | 
|
public static SurfaceManager getManager(Image img) {  | 
|
SurfaceManager sMgr = imgaccessor.getSurfaceManager(img);  | 
|
if (sMgr == null) {  | 
|
            /* | 
|
             * In practice only a BufferedImage will get here. | 
|
*/  | 
|
            try { | 
|
BufferedImage bi = (BufferedImage) img;  | 
|
sMgr = new BufImgSurfaceManager(bi);  | 
|
setManager(bi, sMgr);  | 
|
} catch (ClassCastException e) {  | 
|
throw new IllegalArgumentException("Invalid Image variant");  | 
|
}  | 
|
}  | 
|
return sMgr;  | 
|
}  | 
|
public static void setManager(Image img, SurfaceManager mgr) {  | 
|
imgaccessor.setSurfaceManager(img, mgr);  | 
|
}  | 
|
private ConcurrentHashMap<Object,Object> cacheMap;  | 
|
    /** | 
|
     * Return an arbitrary cached object for an arbitrary cache key. | 
|
     * Other objects can use this mechanism to store cached data about | 
|
     * the source image that will let them save time when using or | 
|
     * manipulating the image in the future. | 
|
     * <p> | 
|
     * Note that the cache is maintained as a simple Map with no | 
|
     * attempts to keep it up to date or invalidate it so any data | 
|
     * stored here must either not be dependent on the state of the | 
|
     * image or it must be individually tracked to see if it is | 
|
     * outdated or obsolete. | 
|
     * <p> | 
|
     * The SurfaceData object of the primary (destination) surface | 
|
     * has a StateTracker mechanism which can help track the validity | 
|
     * and "currentness" of any data stored here. | 
|
     * For convenience and expediency an object stored as cached | 
|
     * data may implement the FlushableCacheData interface specified | 
|
     * below so that it may be notified immediately if the flush() | 
|
     * method is ever called. | 
|
*/  | 
|
public Object getCacheData(Object key) {  | 
|
return (cacheMap == null) ? null : cacheMap.get(key);  | 
|
}  | 
|
    /** | 
|
     * Store an arbitrary cached object for an arbitrary cache key. | 
|
     * See the getCacheData() method for notes on tracking the | 
|
     * validity of data stored using this mechanism. | 
|
*/  | 
|
public void setCacheData(Object key, Object value) {  | 
|
if (cacheMap == null) {  | 
|
            synchronized (this) { | 
|
if (cacheMap == null) {  | 
|
cacheMap = new ConcurrentHashMap<>(2);  | 
|
}  | 
|
}  | 
|
}  | 
|
cacheMap.put(key, value);  | 
|
}  | 
|
    /** | 
|
     * Returns the main SurfaceData object that "owns" the pixels for | 
|
     * this SurfaceManager.  This SurfaceData is used as the destination | 
|
     * surface in a rendering operation and is the most authoritative | 
|
     * storage for the current state of the pixels, though other | 
|
     * versions might be cached in other locations for efficiency. | 
|
*/  | 
|
public abstract SurfaceData getPrimarySurfaceData();  | 
|
    /** | 
|
     * Restores the primary surface being managed, and then returns the | 
|
     * replacement surface.  This is called when an accelerated surface has | 
|
     * been "lost", in an attempt to auto-restore its contents. | 
|
*/  | 
|
public abstract SurfaceData restoreContents();  | 
|
    /** | 
|
     * Notification that any accelerated surfaces associated with this manager | 
|
     * have been "lost", which might mean that they need to be manually | 
|
     * restored or recreated. | 
|
     * | 
|
     * The default implementation does nothing, but platform-specific | 
|
     * variants which have accelerated surfaces should perform any necessary | 
|
     * actions. | 
|
*/  | 
|
    public void acceleratedSurfaceLost() {} | 
|
    /** | 
|
     * Returns an ImageCapabilities object which can be | 
|
     * inquired as to the specific capabilities of this | 
|
     * Image.  The capabilities object will return true for | 
|
     * isAccelerated() if the image has a current and valid | 
|
     * SurfaceDataProxy object cached for the specified | 
|
     * GraphicsConfiguration parameter. | 
|
     * <p> | 
|
     * This class provides a default implementation of the | 
|
     * ImageCapabilities that will try to determine if there | 
|
     * is an associated SurfaceDataProxy object and if it is | 
|
     * up to date, but only works for GraphicsConfiguration | 
|
     * objects which implement the ProxiedGraphicsConfig | 
|
     * interface defined below.  In practice, all configs | 
|
     * which can be accelerated are currently implementing | 
|
     * that interface. | 
|
     * <p> | 
|
     * A null GraphicsConfiguration returns a value based on whether the | 
|
     * image is currently accelerated on its default GraphicsConfiguration. | 
|
     * | 
|
     * @see java.awt.Image#getCapabilities | 
|
     * @since 1.5 | 
|
*/  | 
|
public ImageCapabilities getCapabilities(GraphicsConfiguration gc) {  | 
|
return new ImageCapabilitiesGc(gc);  | 
|
}  | 
|
class ImageCapabilitiesGc extends ImageCapabilities {  | 
|
GraphicsConfiguration gc;  | 
|
public ImageCapabilitiesGc(GraphicsConfiguration gc) {  | 
|
super(false);  | 
|
this.gc = gc;  | 
|
}  | 
|
        public boolean isAccelerated() { | 
|
// Note that when img.getAccelerationPriority() gets set to 0  | 
|
// we remove SurfaceDataProxy objects from the cache and the  | 
|
            // answer will be false. | 
|
GraphicsConfiguration tmpGc = gc;  | 
|
if (tmpGc == null) {  | 
|
tmpGc = GraphicsEnvironment.getLocalGraphicsEnvironment().  | 
|
getDefaultScreenDevice().getDefaultConfiguration();  | 
|
}  | 
|
if (tmpGc instanceof ProxiedGraphicsConfig) {  | 
|
Object proxyKey =  | 
|
((ProxiedGraphicsConfig) tmpGc).getProxyKey();  | 
|
if (proxyKey != null) {  | 
|
SurfaceDataProxy sdp =  | 
|
(SurfaceDataProxy) getCacheData(proxyKey);  | 
|
return (sdp != null && sdp.isAccelerated());  | 
|
}  | 
|
}  | 
|
return false;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * An interface for GraphicsConfiguration objects to implement if | 
|
     * their surfaces accelerate images using SurfaceDataProxy objects. | 
|
     * | 
|
     * Implementing this interface facilitates the default | 
|
     * implementation of getImageCapabilities() above. | 
|
*/  | 
|
    public static interface ProxiedGraphicsConfig { | 
|
        /** | 
|
         * Return the key that destination surfaces created on the | 
|
         * given GraphicsConfiguration use to store SurfaceDataProxy | 
|
         * objects for their cached copies. | 
|
*/  | 
|
public Object getProxyKey();  | 
|
}  | 
|
    /** | 
|
     * Releases system resources in use by ancillary SurfaceData objects, | 
|
     * such as surfaces cached in accelerated memory.  Subclasses should | 
|
     * override to release any of their flushable data. | 
|
     * <p> | 
|
     * The default implementation will visit all of the value objects | 
|
     * in the cacheMap and flush them if they implement the | 
|
     * FlushableCacheData interface. | 
|
*/  | 
|
    public synchronized void flush() { | 
|
flush(false);  | 
|
}  | 
|
    synchronized void flush(boolean deaccelerate) { | 
|
if (cacheMap != null) {  | 
|
Iterator<Object> i = cacheMap.values().iterator();  | 
|
while (i.hasNext()) {  | 
|
Object o = i.next();  | 
|
if (o instanceof FlushableCacheData) {  | 
|
if (((FlushableCacheData) o).flush(deaccelerate)) {  | 
|
i.remove();  | 
|
}  | 
|
}  | 
|
}  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * An interface for Objects used in the SurfaceManager cache | 
|
     * to implement if they have data that should be flushed when | 
|
     * the Image is flushed. | 
|
*/  | 
|
    public static interface FlushableCacheData { | 
|
        /** | 
|
         * Flush all cached resources. | 
|
         * The deaccelerated parameter indicates if the flush is | 
|
         * happening because the associated surface is no longer | 
|
         * being accelerated (for instance the acceleration priority | 
|
         * is set below the threshold needed for acceleration). | 
|
         * Returns a boolean that indicates if the cached object is | 
|
         * no longer needed and should be removed from the cache. | 
|
*/  | 
|
public boolean flush(boolean deaccelerated);  | 
|
}  | 
|
    /** | 
|
     * Called when image's acceleration priority is changed. | 
|
     * <p> | 
|
     * The default implementation will visit all of the value objects | 
|
     * in the cacheMap when the priority gets set to 0.0 and flush them | 
|
     * if they implement the FlushableCacheData interface. | 
|
*/  | 
|
    public void setAccelerationPriority(float priority) { | 
|
if (priority == 0.0f) {  | 
|
flush(true);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns a scale factor of the image. This is utility method, which | 
|
     * fetches information from the SurfaceData of the image. | 
|
     * | 
|
     * @see SurfaceData#getDefaultScale | 
|
*/  | 
|
public static int getImageScale(final Image img) {  | 
|
if (!(img instanceof VolatileImage)) {  | 
|
return 1;  | 
|
}  | 
|
final SurfaceManager sm = getManager(img);  | 
|
return sm.getPrimarySurfaceData().getDefaultScale();  | 
|
}  | 
|
}  |