/* * 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.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. *

* 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. *

* 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. *

* 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. *

* 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. *

* 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. *

* 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. *

* 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); } } }