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 abstract static class ImageAccessor {
getSurfaceManager(Image img)55         public abstract SurfaceManager getSurfaceManager(Image img);
setSurfaceManager(Image img, SurfaceManager mgr)56         public abstract void setSurfaceManager(Image img, SurfaceManager mgr);
57     }
58 
59     private static ImageAccessor imgaccessor;
60 
setImageAccessor(ImageAccessor ia)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      */
getManager(Image img)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 
setManager(Image img, SurfaceManager mgr)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      */
getCacheData(Object key)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      */
setCacheData(Object key, Object value)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      */
getPrimarySurfaceData()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      */
restoreContents()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      */
acceleratedSurfaceLost()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      */
getCapabilities(GraphicsConfiguration gc)184     public ImageCapabilities getCapabilities(GraphicsConfiguration gc) {
185         return new ImageCapabilitiesGc(gc);
186     }
187 
188     class ImageCapabilitiesGc extends ImageCapabilities {
189         GraphicsConfiguration gc;
190 
ImageCapabilitiesGc(GraphicsConfiguration gc)191         public ImageCapabilitiesGc(GraphicsConfiguration gc) {
192             super(false);
193             this.gc = gc;
194         }
195 
isAccelerated()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          */
getProxyKey()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      */
flush()243     public synchronized void flush() {
244         flush(false);
245     }
246 
flush(boolean deaccelerate)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          */
flush(boolean deaccelerated)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      */
setAccelerationPriority(float priority)286     public void setAccelerationPriority(float priority) {
287         if (priority == 0.0f) {
288             flush(true);
289         }
290     }
291 
292     /**
293      * Returns a horizontal scale factor of the image. This is utility method,
294      * which fetches information from the SurfaceData of the image.
295      *
296      * @see SurfaceData#getDefaultScaleX
297      */
getImageScaleX(final Image img)298     public static double getImageScaleX(final Image img) {
299         if (!(img instanceof VolatileImage)) {
300             return 1;
301         }
302         final SurfaceManager sm = getManager(img);
303         return sm.getPrimarySurfaceData().getDefaultScaleX();
304     }
305 
306     /**
307      * Returns a vertical scale factor of the image. This is utility method,
308      * which fetches information from the SurfaceData of the image.
309      *
310      * @see SurfaceData#getDefaultScaleY
311      */
getImageScaleY(final Image img)312     public static double getImageScaleY(final Image img) {
313         if (!(img instanceof VolatileImage)) {
314             return 1;
315         }
316         final SurfaceManager sm = getManager(img);
317         return sm.getPrimarySurfaceData().getDefaultScaleY();
318     }
319 }
320