528 lines · 20.2 KB · Java
RawDownload
/* * Copyright (c) 2007, 2008, 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.java2d; import java.awt.Color;import java.awt.Rectangle;import java.awt.AlphaComposite;import java.awt.GraphicsEnvironment; import sun.awt.DisplayChangedListener;import sun.java2d.StateTrackable.State;import sun.java2d.loops.CompositeType;import sun.java2d.loops.SurfaceType;import sun.java2d.loops.Blit;import sun.java2d.loops.BlitBg;import sun.awt.image.SurfaceManager;import sun.awt.image.SurfaceManager.FlushableCacheData; import java.security.AccessController;import sun.security.action.GetPropertyAction; /** * The proxy class encapsulates the logic for managing alternate * SurfaceData representations of a primary SurfaceData. * The main class will handle tracking the state changes of the * primary SurfaceData and updating the associated SurfaceData * proxy variants. * <p> * Subclasses have 2 main responsibilities: * <ul> * <li> Override the isSupportedOperation() method to determine if *      a given operation can be accelerated with a given source *      SurfaceData * <li> Override the validateSurfaceData() method to create or update *      a given accelerated surface to hold the pixels for the indicated *      source SurfaceData * </ul> * If necessary, a subclass may also override the updateSurfaceData * method to transfer the pixels to the accelerated surface. * By default the parent class will transfer the pixels using a * standard Blit operation between the two SurfaceData objects. */public abstract class SurfaceDataProxy    implements DisplayChangedListener, SurfaceManager.FlushableCacheData{    private static boolean cachingAllowed;    private static int defaultThreshold;     static {        cachingAllowed = true;        String manimg = (String)AccessController.doPrivileged(            new GetPropertyAction("sun.java2d.managedimages"));        if (manimg != null && manimg.equals("false")) {            cachingAllowed = false;            System.out.println("Disabling managed images");        }         defaultThreshold = 1;        String num = (String)AccessController.doPrivileged(            new GetPropertyAction("sun.java2d.accthreshold"));        if (num != null) {            try {                int parsed = Integer.parseInt(num);                if (parsed >= 0) {                    defaultThreshold = parsed;                    System.out.println("New Default Acceleration Threshold: " +                                       defaultThreshold);                }            } catch (NumberFormatException e) {                System.err.println("Error setting new threshold:" + e);            }        }    }     public static boolean isCachingAllowed() {        return cachingAllowed;    }     /**     * Determine if an alternate form for the srcData is needed     * and appropriate from the given operational parameters.     */    public abstract boolean isSupportedOperation(SurfaceData srcData,                                                 int txtype,                                                 CompositeType comp,                                                 Color bgColor);     /**     * Construct an alternate form of the given SurfaceData.     * The contents of the returned SurfaceData may be undefined     * since the calling code will take care of updating the     * contents with a subsequent call to updateSurfaceData.     * <p>     * If the method returns null then there was a problem with     * allocating the accelerated surface.  The getRetryTracker()     * method will be called to track when to attempt another     * revalidation.     */    public abstract SurfaceData validateSurfaceData(SurfaceData srcData,                                                    SurfaceData cachedData,                                                    int w, int h);     /**     * If the subclass is unable to validate or create a cached     * SurfaceData then this method will be used to get a     * StateTracker object that will indicate when to attempt     * to validate the surface again.  Subclasses may return     * trackers which count down an ever increasing threshold     * to provide hysteresis on creating surfaces during low     * memory conditions.  The default implementation just waits     * another "threshold" number of accesses before trying again.     */    public StateTracker getRetryTracker(SurfaceData srcData) {        return new CountdownTracker(threshold);    }     public static class CountdownTracker implements StateTracker {        private int countdown;         public CountdownTracker(int threshold) {            this.countdown = threshold;        }         public synchronized boolean isCurrent() {            return (--countdown >= 0);        }    }     /**     * This instance is for cases where a caching implementation     * determines that a particular source image will never need     * to be cached - either the source SurfaceData was of an     * incompatible type, or it was in an UNTRACKABLE state or     * some other factor is discovered that permanently prevents     * acceleration or caching.     * This class optimally implements NOP variants of all necessary     * methods to avoid caching with a minimum of fuss.     */    public static SurfaceDataProxy UNCACHED = new SurfaceDataProxy(0) {        @Override        public boolean isAccelerated() {            return false;        }         @Override        public boolean isSupportedOperation(SurfaceData srcData,                                            int txtype,                                            CompositeType comp,                                            Color bgColor)        {            return false;        }         @Override        public SurfaceData validateSurfaceData(SurfaceData srcData,                                               SurfaceData cachedData,                                               int w, int h)        {            throw new InternalError("UNCACHED should never validate SDs");        }         @Override        public SurfaceData replaceData(SurfaceData srcData,                                       int txtype,                                       CompositeType comp,                                       Color bgColor)        {            // Not necessary to override this, but doing so is faster            return srcData;        }    };     // The number of attempts to copy from a STABLE source before    // a cached copy is created or updated.    private int threshold;     /*     * Source tracking data     *     * Every time that srcTracker is out of date we will reset numtries     * to threshold and set the cacheTracker to one that is non-current.     * numtries will then count down to 0 at which point the cacheTracker     * will remind us that we need to update the cachedSD before we can     * use it.     *     * Note that since these fields interrelate we should synchronize     * whenever we update them, but it should be OK to read them     * without synchronization.     */    private StateTracker srcTracker;    private int numtries;     /*     * Cached data     *     * We cache a SurfaceData created by the subclass in cachedSD and     * track its state (isValid and !surfaceLost) in cacheTracker.     *     * Also, when we want to note that cachedSD needs to be updated     * we replace the cacheTracker with a NEVER_CURRENT tracker which     * will cause us to try to revalidate and update the surface on     * next use.     */    private SurfaceData cachedSD;    private StateTracker cacheTracker;     /*     * Are we still the best object to control caching of data     * for the source image?     */    private boolean valid;     /**     * Create a SurfaceData proxy manager that attempts to create     * and cache a variant copy of the source SurfaceData after     * the default threshold number of attempts to copy from the     * STABLE source.     */    public SurfaceDataProxy() {        this(defaultThreshold);    }     /**     * Create a SurfaceData proxy manager that attempts to create     * and cache a variant copy of the source SurfaceData after     * the specified threshold number of attempts to copy from     * the STABLE source.     */    public SurfaceDataProxy(int threshold) {        this.threshold = threshold;         this.srcTracker = StateTracker.NEVER_CURRENT;        // numtries will be reset on first use        this.cacheTracker = StateTracker.NEVER_CURRENT;         this.valid = true;    }     /**     * Returns true iff this SurfaceData proxy is still the best     * way to control caching of the given source on the given     * destination.     */    public boolean isValid() {        return valid;    }     /**     * Sets the valid state to false so that the next time this     * proxy is fetched to generate a replacement SurfaceData,     * the code in SurfaceData knows to replace the proxy first.     */    public void invalidate() {        this.valid = false;    }     /**     * Flush all cached resources as per the FlushableCacheData interface.     * 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) {        if (deaccelerated) {            invalidate();        }        flush();        return !isValid();    }     /**     * Actively flushes (drops and invalidates) the cached surface     * so that it can be reclaimed quickly.     */    public synchronized void flush() {        SurfaceData csd = this.cachedSD;        this.cachedSD = null;        this.cacheTracker = StateTracker.NEVER_CURRENT;        if (csd != null) {            csd.flush();        }    }     /**     * Returns true iff this SurfaceData proxy is still valid     * and if it has a currently cached replacement that is also     * valid and current.     */    public boolean isAccelerated() {        return (isValid() &&                srcTracker.isCurrent() &&                cacheTracker.isCurrent());    }     /**     * This method should be called from subclasses which create     * cached SurfaceData objects that depend on the current     * properties of the display.     */    protected void activateDisplayListener() {        GraphicsEnvironment ge =            GraphicsEnvironment.getLocalGraphicsEnvironment();        // We could have a HeadlessGE at this point, so double-check before        // assuming anything.        // Also, no point in listening to display change events if        // the image is never going to be accelerated.        if (ge instanceof SunGraphicsEnvironment) {            ((SunGraphicsEnvironment)ge).addDisplayChangedListener(this);        }    }     /**     * Invoked when the display mode has changed.     * This method will invalidate and drop the internal cachedSD object.     */    public void displayChanged() {        flush();    }     /**     * Invoked when the palette has changed.     */    public void paletteChanged() {        // We could potentially get away with just resetting cacheTracker        // here but there is a small window of vulnerability in the        // replaceData method where we could be just finished with        // updating the cachedSD when this method is called and even        // though we set a non-current cacheTracker here it will then        // immediately get set to a current one by the thread that is        // updating the cachedSD.  It is safer to just replace the        // srcTracker with a non-current version that will trigger a        // full update cycle the next time this proxy is used.        // The downside is having to go through a full threshold count        // before we can update and use our cache again, but palette        // changes should be relatively rare...        this.srcTracker = StateTracker.NEVER_CURRENT;    }     /**     * This method attempts to replace the srcData with a cached version.     * It relies on the subclass to determine if the cached version will     * be useful given the operational parameters.     * This method checks any preexisting cached copy for being "up to date"     * and tries to update it if it is stale or non-existant and the     * appropriate number of accesses have occured since it last was stale.     * <p>     * An outline of the process is as follows:     * <ol>     * <li> Check the operational parameters (txtype, comp, bgColor)     *      to make sure that the operation is supported.  Return the     *      original SurfaceData if the operation cannot be accelerated.     * <li> Check the tracker for the source surface to see if it has     *      remained stable since it was last cached.  Update the state     *      variables to cause both a threshold countdown and an update     *      of the cached copy if it is not.  (Setting cacheTracker to     *      NEVER_CURRENT effectively marks it as "needing to be updated".)     * <li> Check the tracker for the cached copy to see if is still     *      valid and up to date.  Note that the cacheTracker may be     *      non-current if either something happened to the cached copy     *      (eg. surfaceLost) or if the source was out of date and the     *      cacheTracker was set to NEVER_CURRENT to force an update.     *      Decrement the countdown and copy the source to the cache     *      as necessary and then update the variables to show that     *      the cached copy is stable.     * </ol>     */    public SurfaceData replaceData(SurfaceData srcData,                                   int txtype,                                   CompositeType comp,                                   Color bgColor)    {        if (isSupportedOperation(srcData, txtype, comp, bgColor)) {            // First deal with tracking the source.            if (!srcTracker.isCurrent()) {                synchronized (this) {                    this.numtries = threshold;                    this.srcTracker = srcData.getStateTracker();                    this.cacheTracker = StateTracker.NEVER_CURRENT;                }                 if (!srcTracker.isCurrent()) {                    // Dynamic or Untrackable (or a very recent modification)                    if (srcData.getState() == State.UNTRACKABLE) {                        // UNTRACKABLE means we can never cache again.                         // Invalidate so we get replaced next time we are used                        // (presumably with an UNCACHED proxy).                        invalidate();                         // Aggressively drop our reference to the cachedSD                        // in case this proxy is not consulted again (and                        // thus replaced) for a long time.                        flush();                    }                    return srcData;                }            }             // Then deal with checking the validity of the cached SurfaceData            SurfaceData csd = this.cachedSD;            if (!cacheTracker.isCurrent()) {                // Next make sure the dust has settled                synchronized (this) {                    if (numtries > 0) {                        --numtries;                        return srcData;                    }                }                 Rectangle r = srcData.getBounds();                int w = r.width;                int h = r.height;                 // Snapshot the tracker in case it changes while                // we are updating the cached SD...                StateTracker curTracker = srcTracker;                 csd = validateSurfaceData(srcData, csd, w, h);                if (csd == null) {                    synchronized (this) {                        if (curTracker == srcTracker) {                            this.cacheTracker = getRetryTracker(srcData);                            this.cachedSD = null;                        }                    }                    return srcData;                }                 updateSurfaceData(srcData, csd, w, h);                if (!csd.isValid()) {                    return srcData;                }                 synchronized (this) {                    // We only reset these variables if the tracker from                    // before the surface update is still in use and current                    // Note that we must use a srcTracker that was fetched                    // from before the update process to make sure that we                    // do not lose some pixel changes in the shuffle.                    if (curTracker == srcTracker && curTracker.isCurrent()) {                        this.cacheTracker = csd.getStateTracker();                        this.cachedSD = csd;                    }                }            }             if (csd != null) {                return csd;            }        }         return srcData;    }     /**     * This is the default implementation for updating the cached     * SurfaceData from the source (primary) SurfaceData.     * A simple Blit is used to copy the pixels from the source to     * the destination SurfaceData.     * A subclass can override this implementation if a more complex     * operation is required to update its cached copies.     */    public void updateSurfaceData(SurfaceData srcData,                                  SurfaceData dstData,                                  int w, int h)    {        SurfaceType srcType = srcData.getSurfaceType();        SurfaceType dstType = dstData.getSurfaceType();        Blit blit = Blit.getFromCache(srcType,                                      CompositeType.SrcNoEa,                                      dstType);        blit.Blit(srcData, dstData,                  AlphaComposite.Src, null,                  0, 0, 0, 0, w, h);

Lines 1–500 of 528.