litesoft
@ 950
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.gen2.event.shared; import com.google.gwt.core.client.*; import com.google.gwt.gen2.event.shared.AbstractEvent.*; /** * Default JavaScript handler registry. This is in the shared package so we * don't have to make it public, should never be called outside of a GWT runtime * environment. * <p/> * Th JsHandlerRegistry makes use of the fact that in the large majority of * cases, only one or two handlers are added for each event type. Therefore, * rather than storing handlers in a list of lists, we store then in a single * flattened array with an escape clause to handle the rare case where we have * more handlers then expected. */ class JsHandlerRegistry extends JavaScriptObject { public static JsHandlerRegistry create() { return (JsHandlerRegistry) JavaScriptObject.createObject(); } /** * Required constructor. */ protected JsHandlerRegistry() { } public final void addHandler( AbstractEvent.Type eventKey, EventHandler handler ) { // The base is the equivalent to a c pointer into the flattened handler data // structure. int base = eventKey.hashCode(); int count = getCount( base ); // If we already have the maximum number of handlers we can store in the // flattened data structure, store the handlers in an external list instead. if ( count == HandlerManager.EXPECTED_HANDLERS && isFlattened( base ) ) { unflatten( base ); } setHandler( base, count, handler, isFlattened( base ) ); setCount( base, count + 1 ); } public final void clearHandlers( Type<?, ?> type ) { int base = type.hashCode(); // Clearing handlers is relatively unusual, so the cost of unflattening the // handler list is justified by the smaller code. unflatten( base ); // Replace the list of handlers. setHandlerList( base + 1, JavaScriptObject.createArray() ); setCount( base, 0 ); } public final void fireEvent( AbstractEvent event ) { Type type = event.getType(); int base = type.hashCode(); int count = getCount( base ); boolean isFlattened = isFlattened( base ); for ( int i = 0; i < count; i++ ) { // Gets the given handler to fire. EventHandler handler = getHandler( base, i, isFlattened ); // Fires the handler. type.fire( handler, event ); } } public final EventHandler getHandler( AbstractEvent.Type eventKey, int index ) { int base = eventKey.hashCode(); int count = getCount( base ); if ( index >= count ) { throw new IndexOutOfBoundsException( "index: " + index ); } return getHandler( base, index, isFlattened( base ) ); } public final int getHandlerCount( AbstractEvent.Type eventKey ) { return getCount( eventKey.hashCode() ); } public final void removeHandler( AbstractEvent.Type eventKey, EventHandler handler ) { int base = eventKey.hashCode(); // Removing a handler is unusual, so smaller code is preferable then // handling both flat and dangling list of pointers. if ( isFlattened( base ) ) { unflatten( base ); } boolean result = removeHelper( base, handler ); // Hiding this behind an assertion as we'd rather not force the compiler to // have to include all handler.toString() instances. assert result : handler + " did not exist"; } private native int getCount( int index ) /*-{ var count = this[index]; return count == null ? 0 : count; }-*/; private native EventHandler getHandler( int base, int index, boolean flattened ) /*-{ return flattened ? this[base + 2 + index] : this[base + 1][index]; }-*/; private native boolean isFlattened( int base ) /*-{ return this[base + 1] == null; }-*/; private native boolean removeHelper( int base, EventHandler handler ) /*-{ // Find the handler. var count = this[base]; var handlerList = this[base + 1]; var handlerIndex = -1; for ( var index = 0; index < count; index++ ) { if ( handlerList[index] == handler ) { handlerIndex = index; break; } } if ( handlerIndex == -1 ) { return false; } // Remove the handler. var last = count - 1; for ( ; handlerIndex < last; handlerIndex++ ) { handlerList[handlerIndex] = handlerList[handlerIndex + 1] } handlerList[last] = null; this[base] = this[base] - 1; return true; }-*/; private native void setCount( int index, int count ) /*-{ this[index] = count; }-*/; private native void setHandler( int base, int index, EventHandler handler, boolean flattened ) /*-{ if ( flattened ) { this[base + 2 + index] = handler; } else { this[base + 1][index] = handler; } }-*/; private native void setHandlerList( int base, JavaScriptObject handlerList ) /*-{ this[base + 1] = handlerList; }-*/; private native void unflatten( int base ) /*-{ var handlerList = {}; var count = this[base]; var start = base + 2; for ( var i = 0; i < count; i++ ) { handlerList[i] = this[start + i]; this[start + i] = null; } this[base + 1] = handlerList; }-*/; } |