blob: 878f0a7e7d33d42c3c272f33187cf5121c222c2f [file] [log] [blame]
/*
* Copyright (c) 2003, 2007, 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 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 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();
}
}