31
31
import java .awt .ImageCapabilities ;
32
32
import java .awt .image .BufferedImage ;
33
33
import java .awt .image .VolatileImage ;
34
+ import java .lang .ref .WeakReference ;
35
+ import java .util .Collections ;
34
36
import java .util .Iterator ;
35
- import java .util .concurrent .ConcurrentHashMap ;
37
+ import java .util .Map ;
38
+ import java .util .WeakHashMap ;
36
39
37
40
import sun .java2d .InvalidPipeException ;
38
41
import sun .java2d .SurfaceData ;
@@ -89,47 +92,14 @@ public static void setManager(Image img, SurfaceManager mgr) {
89
92
imgaccessor .setSurfaceManager (img , mgr );
90
93
}
91
94
92
- private volatile 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
- */
114
- public Object getCacheData (Object key ) {
115
- return (cacheMap == null ) ? null : cacheMap .get (key );
116
- }
117
-
118
95
/**
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.
96
+ * This map holds references to SurfaceDataProxy per given ProxyCache.
97
+ * Unlike ProxyCache, which contains SurfaceDataProxy objects per given SurfaceManager,
98
+ * this map does not prevent contained proxies from being garbage collected.
99
+ * Therefore, ProxyCache can be considered an "owning" container for the SurfaceDataProxy objects,
100
+ * and this map is just a weak mapping for the bookkeeping purposes.
122
101
*/
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
- }
102
+ private final Map <ProxyCache , WeakReference <SurfaceDataProxy >> weakCache = new WeakHashMap <>(2 );
133
103
134
104
/**
135
105
* Returns the main SurfaceData object that "owns" the pixels for
@@ -202,12 +172,10 @@ public boolean isAccelerated() {
202
172
tmpGc = GraphicsEnvironment .getLocalGraphicsEnvironment ().
203
173
getDefaultScreenDevice ().getDefaultConfiguration ();
204
174
}
205
- if (tmpGc instanceof ProxiedGraphicsConfig ) {
206
- Object proxyKey =
207
- ((ProxiedGraphicsConfig ) tmpGc ).getProxyKey ();
208
- if (proxyKey != null ) {
209
- SurfaceDataProxy sdp =
210
- (SurfaceDataProxy ) getCacheData (proxyKey );
175
+ if (tmpGc instanceof ProxiedGraphicsConfig pgc ) {
176
+ ProxyCache cache = pgc .getSurfaceDataProxyCache ();
177
+ if (cache != null ) {
178
+ SurfaceDataProxy sdp = cache .get (SurfaceManager .this );
211
179
return (sdp != null && sdp .isAccelerated ());
212
180
}
213
181
}
@@ -222,13 +190,51 @@ public boolean isAccelerated() {
222
190
* Implementing this interface facilitates the default
223
191
* implementation of getImageCapabilities() above.
224
192
*/
225
- public static interface ProxiedGraphicsConfig {
193
+ public interface ProxiedGraphicsConfig {
194
+
226
195
/**
227
- * Return the key that destination surfaces created on the
196
+ * Return the cache that destination surfaces created on the
228
197
* given GraphicsConfiguration use to store SurfaceDataProxy
229
198
* objects for their cached copies.
230
199
*/
231
- public Object getProxyKey ();
200
+ ProxyCache getSurfaceDataProxyCache ();
201
+ }
202
+
203
+ public static class ProxyCache {
204
+ private final Map <SurfaceManager , SurfaceDataProxy > map = Collections .synchronizedMap (new WeakHashMap <>());
205
+
206
+ /**
207
+ * Return a cached SurfaceDataProxy object for a given SurfaceManager.
208
+ * <p>
209
+ * Note that the cache is maintained as a simple Map with no
210
+ * attempts to keep it up to date or invalidate it so any data
211
+ * stored here must either not be dependent on the state of the
212
+ * image or it must be individually tracked to see if it is
213
+ * outdated or obsolete.
214
+ * <p>
215
+ * The SurfaceData object of the primary (destination) surface
216
+ * has a StateTracker mechanism which can help track the validity
217
+ * and "currentness" of any data stored here.
218
+ * For convenience and expediency an object stored as cached
219
+ * data may implement the FlushableCacheData interface specified
220
+ * below so that it may be notified immediately if the flush()
221
+ * method is ever called.
222
+ */
223
+ public SurfaceDataProxy get (SurfaceManager manager ) {
224
+ return map .get (manager );
225
+ }
226
+
227
+ /**
228
+ * Store a cached SurfaceDataProxy object for a given SurfaceManager.
229
+ * See the get() method for notes on tracking the
230
+ * validity of data stored using this mechanism.
231
+ */
232
+ public void put (SurfaceManager manager , SurfaceDataProxy proxy ) {
233
+ synchronized (manager .weakCache ) { // Synchronize on weakCache first!
234
+ manager .weakCache .put (this , new WeakReference <>(proxy ));
235
+ map .put (manager , proxy );
236
+ }
237
+ }
232
238
}
233
239
234
240
/**
@@ -244,15 +250,13 @@ public synchronized void flush() {
244
250
flush (false );
245
251
}
246
252
247
- synchronized void flush (boolean deaccelerate ) {
248
- if ( cacheMap != null ) {
249
- Iterator <Object > i = cacheMap .values ().iterator ();
253
+ void flush (boolean deaccelerate ) {
254
+ synchronized ( weakCache ) {
255
+ Iterator <WeakReference < SurfaceDataProxy >> i = weakCache .values ().iterator ();
250
256
while (i .hasNext ()) {
251
- Object o = i .next ();
252
- if (o instanceof FlushableCacheData ) {
253
- if (((FlushableCacheData ) o ).flush (deaccelerate )) {
254
- i .remove ();
255
- }
257
+ SurfaceDataProxy sdp = i .next ().get ();
258
+ if (sdp == null || sdp .flush (deaccelerate )) {
259
+ i .remove ();
256
260
}
257
261
}
258
262
}
0 commit comments