1 /*
   2  * Copyright (c) 2007, 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.java2d;
  27 
  28 import sun.java2d.StateTrackable.State;
  29 import static sun.java2d.StateTrackable.State.*;
  30 
  31 /**
  32  * This class provides a basic pre-packaged implementation of the
  33  * complete {@link StateTrackable} interface with implementations
  34  * of the required methods in the interface and methods to manage
  35  * transitions in the state of the object.
  36  * Classes which wish to implement StateTrackable could create an
  37  * instance of this class and delegate all of their implementations
  38  * for {@code StateTrackable} methods to the corresponding methods
  39  * of this class.
  40  */
  41 public final class StateTrackableDelegate implements StateTrackable {
  42     /**
  43      * The {@code UNTRACKABLE_DELEGATE} provides an implementation
  44      * of the StateTrackable interface that is permanently in the
  45      * {@link State#UNTRACKABLE UNTRACKABLE} state.
  46      */
  47     public final static StateTrackableDelegate UNTRACKABLE_DELEGATE =
  48         new StateTrackableDelegate(UNTRACKABLE);
  49 
  50     /**
  51      * The {@code IMMUTABLE_DELEGATE} provides an implementation
  52      * of the StateTrackable interface that is permanently in the
  53      * {@link State#IMMUTABLE IMMUTABLE} state.
  54      */
  55     public final static StateTrackableDelegate IMMUTABLE_DELEGATE =
  56         new StateTrackableDelegate(IMMUTABLE);
  57 
  58     /**
  59      * Returns a {@code StateTrackableDelegate} instance with the
  60      * specified initial {@link State State}.
  61      * If the specified {@code State} is
  62      * {@link State#UNTRACKABLE UNTRACKABLE} or
  63      * {@link State#IMMUTABLE IMMUTABLE}
  64      * then the approprirate static instance
  65      * {@link #UNTRACKABLE_DELEGATE} or {@link #IMMUTABLE_DELEGATE}
  66      * is returned.
  67      */
  68     public static StateTrackableDelegate createInstance(State state) {
  69         switch (state) {
  70         case UNTRACKABLE:
  71             return UNTRACKABLE_DELEGATE;
  72         case STABLE:
  73             return new StateTrackableDelegate(STABLE);
  74         case DYNAMIC:
  75             return new StateTrackableDelegate(DYNAMIC);
  76         case IMMUTABLE:
  77             return IMMUTABLE_DELEGATE;
  78         default:
  79             throw new InternalError("unknown state");
  80         }
  81     }
  82 
  83     private State theState;
  84     StateTracker theTracker;   // package private for easy access from tracker
  85     private int numDynamicAgents;
  86 
  87     /**
  88      * Constructs a StateTrackableDelegate object with the specified
  89      * initial State.
  90      */
  91     private StateTrackableDelegate(State state) {
  92         this.theState = state;
  93     }
  94 
  95     /**
  96      * @inheritDoc
  97      * @since 1.7
  98      */
  99     public State getState() {
 100         return theState;
 101     }
 102 
 103     /**
 104      * @inheritDoc
 105      * @since 1.7
 106      */
 107     public synchronized StateTracker getStateTracker() {
 108         StateTracker st = theTracker;
 109         if (st == null) {
 110             switch (theState) {
 111             case IMMUTABLE:
 112                 st = StateTracker.ALWAYS_CURRENT;
 113                 break;
 114             case STABLE:
 115                 st = new StateTracker() {
 116                     public boolean isCurrent() {
 117                         return (theTracker == this);
 118                     }
 119                 };
 120                 break;
 121             case DYNAMIC:
 122                 // We return the NEVER_CURRENT tracker, but that is
 123                 // just temporary while we are in the DYNAMIC state.
 124                 // NO BREAK
 125             case UNTRACKABLE:
 126                 st = StateTracker.NEVER_CURRENT;
 127                 break;
 128             }
 129             theTracker = st;
 130         }
 131         return st;
 132     }
 133 
 134     /**
 135      * This method provides an easy way for delegating classes to
 136      * change the overall {@link State State} of the delegate to
 137      * {@link State#IMMUTABLE IMMUTABLE}.
 138      * @throws IllegalStateException if the current state is
 139      *         {@link State#UNTRACKABLE UNTRACKABLE}
 140      * @see #setUntrackable
 141      * @since 1.7
 142      */
 143     public synchronized void setImmutable() {
 144         if (theState == UNTRACKABLE || theState == DYNAMIC) {
 145             throw new IllegalStateException("UNTRACKABLE or DYNAMIC "+
 146                                             "objects cannot become IMMUTABLE");
 147         }
 148         theState = IMMUTABLE;
 149         theTracker = null;
 150     }
 151 
 152     /**
 153      * This method provides an easy way for delegating classes to
 154      * change the overall {@link State State} of the delegate to
 155      * {@link State#UNTRACKABLE UNTRACKABLE}.
 156      * This method is typically called when references to the
 157      * internal data buffers have been made public.
 158      * @throws IllegalStateException if the current state is
 159      *         {@link State#IMMUTABLE IMMUTABLE}
 160      * @see #setImmutable
 161      * @since 1.7
 162      */
 163     public synchronized void setUntrackable() {
 164         if (theState == IMMUTABLE) {
 165             throw new IllegalStateException("IMMUTABLE objects cannot "+
 166                                             "become UNTRACKABLE");
 167         }
 168         theState = UNTRACKABLE;
 169         theTracker = null;
 170     }
 171 
 172     /**
 173      * This method provides an easy way for delegating classes to
 174      * manage temporarily setting the overall {@link State State}
 175      * of the delegate to {@link State#DYNAMIC DYNAMIC}
 176      * during well-defined time frames of dynamic pixel updating.
 177      * This method should be called once before each flow of control
 178      * that might dynamically update the pixels in an uncontrolled
 179      * or unpredictable fashion.
 180      * <p>
 181      * The companion method {@link #removeDynamicAgent} method should
 182      * also be called once after each such flow of control has ended.
 183      * Failing to call the remove method will result in this object
 184      * permanently becoming {@link State#DYNAMIC DYNAMIC}
 185      * and therefore effectively untrackable.
 186      * <p>
 187      * This method will only change the {@link State State} of the
 188      * delegate if it is currently {@link State#STABLE STABLE}.
 189      *
 190      * @throws IllegalStateException if the current state is
 191      *         {@link State#IMMUTABLE IMMUTABLE}
 192      * @since 1.7
 193      */
 194     public synchronized void addDynamicAgent() {
 195         if (theState == IMMUTABLE) {
 196             throw new IllegalStateException("Cannot change state from "+
 197                                             "IMMUTABLE");
 198         }
 199         ++numDynamicAgents;
 200         if (theState == STABLE) {
 201             theState = DYNAMIC;
 202             theTracker = null;
 203         }
 204     }
 205 
 206     /**
 207      * This method provides an easy way for delegating classes to
 208      * manage restoring the overall {@link State State} of the
 209      * delegate back to {@link State#STABLE STABLE}
 210      * after a well-defined time frame of dynamic pixel updating.
 211      * This method should be called once after each flow of control
 212      * that might dynamically update the pixels in an uncontrolled
 213      * or unpredictable fashion has ended.
 214      * <p>
 215      * The companion method {@link #addDynamicAgent} method should
 216      * have been called at some point before each such flow of
 217      * control began.
 218      * If this method is called without having previously called
 219      * the add method, the {@link State State} of this object
 220      * will become unreliable.
 221      * <p>
 222      * This method will only change the {@link State State} of the
 223      * delegate if the number of outstanding dynamic agents has
 224      * gone to 0 and it is currently
 225      * {@link State#DYNAMIC DYNAMIC}.
 226      *
 227      * @since 1.7
 228      */
 229     protected synchronized void removeDynamicAgent() {
 230         if (--numDynamicAgents == 0 && theState == DYNAMIC) {
 231             theState = STABLE;
 232             theTracker = null;
 233         }
 234     }
 235 
 236     /**
 237      * This method provides an easy way for delegating classes to
 238      * indicate that the contents have changed.
 239      * This method will invalidate outstanding StateTracker objects
 240      * so that any other agents which maintain cached information
 241      * about the pixels will know to refresh their cached copies.
 242      * This method should be called after every modification to
 243      * the data, such as any calls to any of the setElem methods.
 244      * <p>
 245      * Note that, for efficiency, this method does not check the
 246      * {@link State State} of the object to see if it is compatible
 247      * with being marked dirty
 248      * (i.e. not {@link State#IMMUTABLE IMMUTABLE}).
 249      * It is up to the callers to enforce the fact that an
 250      * {@code IMMUTABLE} delegate is never modified.
 251      * @since 1.7
 252      */
 253     public void markDirty() {
 254         theTracker = null;
 255     }
 256 }