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 }