Home » openjdk-7 » javax.swing.plaf.nimbus » [javadoc | source]

    1   /*
    2    * Copyright (c) 2005, 2006, 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   package javax.swing.plaf.nimbus;
   26   
   27   import java.awt.GraphicsConfiguration;
   28   import java.awt.Image;
   29   import java.lang.ref.ReferenceQueue;
   30   import java.lang.ref.SoftReference;
   31   import java.util.Arrays;
   32   import java.util.Iterator;
   33   import java.util.LinkedHashMap;
   34   import java.util.Map;
   35   import java.util.concurrent.locks.ReadWriteLock;
   36   import java.util.concurrent.locks.ReentrantReadWriteLock;
   37   
   38   /**
   39    * ImageCache - A fixed pixel count sized cache of Images keyed by arbitrary set of arguments. All images are held with
   40    * SoftReferences so they will be dropped by the GC if heap memory gets tight. When our size hits max pixel count least
   41    * recently requested images are removed first.
   42    *
   43    * @author Created by Jasper Potts (Aug 7, 2007)
   44    */
   45   class ImageCache {
   46       // Ordered Map keyed by args hash, ordered by most recent accessed entry.
   47       private final LinkedHashMap<Integer, PixelCountSoftReference> map =
   48               new LinkedHashMap<Integer, PixelCountSoftReference>(16, 0.75f, true);
   49       // Maximum number of pixels to cache, this is used if maxCount
   50       private final int maxPixelCount;
   51       // Maximum cached image size in pxiels
   52       private final int maxSingleImagePixelSize;
   53       // The current number of pixels stored in the cache
   54       private int currentPixelCount = 0;
   55       // Lock for concurrent access to map
   56       private ReadWriteLock lock = new ReentrantReadWriteLock();
   57       // Reference queue for tracking lost softreferences to images in the cache
   58       private ReferenceQueue<Image> referenceQueue = new ReferenceQueue<Image>();
   59       // Singleton Instance
   60       private static final ImageCache instance = new ImageCache();
   61   
   62   
   63       /** Get static singleton instance */
   64       static ImageCache getInstance() {
   65           return instance;
   66       }
   67   
   68       public ImageCache() {
   69           this.maxPixelCount = (8 * 1024 * 1024) / 4; // 8Mb of pixels
   70           this.maxSingleImagePixelSize = 300 * 300;
   71       }
   72   
   73       public ImageCache(int maxPixelCount, int maxSingleImagePixelSize) {
   74           this.maxPixelCount = maxPixelCount;
   75           this.maxSingleImagePixelSize = maxSingleImagePixelSize;
   76       }
   77   
   78       /** Clear the cache */
   79       public void flush() {
   80           lock.readLock().lock();
   81           try {
   82               map.clear();
   83           } finally {
   84               lock.readLock().unlock();
   85           }
   86       }
   87   
   88       /**
   89        * Check if the image size is to big to be stored in the cache
   90        *
   91        * @param w The image width
   92        * @param h The image height
   93        * @return True if the image size is less than max
   94        */
   95       public boolean isImageCachable(int w, int h) {
   96           return (w * h) < maxSingleImagePixelSize;
   97       }
   98   
   99       /**
  100        * Get the cached image for given keys
  101        *
  102        * @param config The graphics configuration, needed if cached image is a Volatile Image. Used as part of cache key
  103        * @param w      The image width, used as part of cache key
  104        * @param h      The image height, used as part of cache key
  105        * @param args   Other arguments to use as part of the cache key
  106        * @return Returns the cached Image, or null there is no cached image for key
  107        */
  108       public Image getImage(GraphicsConfiguration config, int w, int h, Object... args) {
  109           lock.readLock().lock();
  110           try {
  111               PixelCountSoftReference ref = map.get(hash(config, w, h, args));
  112               // check reference has not been lost and the key truly matches, in case of false positive hash match
  113               if (ref != null && ref.equals(config,w, h, args)) {
  114                   return ref.get();
  115               } else {
  116                   return null;
  117               }
  118           } finally {
  119               lock.readLock().unlock();
  120           }
  121       }
  122   
  123       /**
  124        * Sets the cached image for the specified constraints.
  125        *
  126        * @param image  The image to store in cache
  127        * @param config The graphics configuration, needed if cached image is a Volatile Image. Used as part of cache key
  128        * @param w      The image width, used as part of cache key
  129        * @param h      The image height, used as part of cache key
  130        * @param args   Other arguments to use as part of the cache key
  131        * @return true if the image could be cached or false if the image is too big
  132        */
  133       public boolean setImage(Image image, GraphicsConfiguration config, int w, int h, Object... args) {
  134           if (!isImageCachable(w, h)) return false;
  135           int hash = hash(config, w, h, args);
  136           lock.writeLock().lock();
  137           try {
  138               PixelCountSoftReference ref = map.get(hash);
  139               // check if currently in map
  140               if (ref != null && ref.get() == image) {
  141                   return true;
  142               }
  143               // clear out old
  144               if (ref != null) {
  145                   currentPixelCount -= ref.pixelCount;
  146                   map.remove(hash);
  147               }
  148               // add new image to pixel count
  149               int newPixelCount = image.getWidth(null) * image.getHeight(null);
  150               currentPixelCount += newPixelCount;
  151               // clean out lost references if not enough space
  152               if (currentPixelCount > maxPixelCount) {
  153                   while ((ref = (PixelCountSoftReference)referenceQueue.poll()) != null){
  154                       //reference lost
  155                       map.remove(ref.hash);
  156                       currentPixelCount -= ref.pixelCount;
  157                   }
  158               }
  159               // remove old items till there is enough free space
  160               if (currentPixelCount > maxPixelCount) {
  161                   Iterator<Map.Entry<Integer, PixelCountSoftReference>> mapIter = map.entrySet().iterator();
  162                   while ((currentPixelCount > maxPixelCount) && mapIter.hasNext()) {
  163                       Map.Entry<Integer, PixelCountSoftReference> entry = mapIter.next();
  164                       mapIter.remove();
  165                       Image img = entry.getValue().get();
  166                       if (img != null) img.flush();
  167                       currentPixelCount -= entry.getValue().pixelCount;
  168                   }
  169               }
  170               // finaly put new in map
  171               map.put(hash, new PixelCountSoftReference(image, referenceQueue, newPixelCount,hash, config, w, h, args));
  172               return true;
  173           } finally {
  174               lock.writeLock().unlock();
  175           }
  176       }
  177   
  178       /** Create a unique hash from all the input */
  179       private int hash(GraphicsConfiguration config, int w, int h, Object ... args) {
  180           int hash;
  181           hash = (config != null ? config.hashCode() : 0);
  182           hash = 31 * hash + w;
  183           hash = 31 * hash + h;
  184           hash = 31 * hash + Arrays.deepHashCode(args);
  185           return hash;
  186       }
  187   
  188   
  189       /** Extended SoftReference that stores the pixel count even after the image is lost */
  190       private static class PixelCountSoftReference extends SoftReference<Image> {
  191           private final int pixelCount;
  192           private final int hash;
  193           // key parts
  194           private final GraphicsConfiguration config;
  195           private final int w;
  196           private final int h;
  197           private final Object[] args;
  198   
  199           public PixelCountSoftReference(Image referent, ReferenceQueue<? super Image> q, int pixelCount, int hash,
  200                                          GraphicsConfiguration config, int w, int h, Object[] args) {
  201               super(referent, q);
  202               this.pixelCount = pixelCount;
  203               this.hash = hash;
  204               this.config = config;
  205               this.w = w;
  206               this.h = h;
  207               this.args = args;
  208           }
  209   
  210           public boolean equals (GraphicsConfiguration config, int w, int h, Object[] args){
  211               return config == this.config &&
  212                               w == this.w &&
  213                               h == this.h &&
  214                               Arrays.equals(args, this.args);
  215           }
  216       }
  217   }

Home » openjdk-7 » javax.swing.plaf.nimbus » [javadoc | source]