1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "SkEventSink.h" 11 #include "SkTagList.h" 12 #include "SkThread.h" 13 14 #include "SkThread.h" 15 #include "SkTime.h" 16 17 SK_DEFINE_INST_COUNT(SkEventSink) 18 19 class SkEventSink_Globals { 20 public: 21 SkEventSink_Globals() { 22 fNextSinkID = 0; 23 fSinkHead = NULL; 24 } 25 26 SkMutex fSinkMutex; 27 SkEventSinkID fNextSinkID; 28 SkEventSink* fSinkHead; 29 }; 30 31 static SkEventSink_Globals& getGlobals() { 32 // leak this, so we don't incur any shutdown perf hit 33 static SkEventSink_Globals* gGlobals = new SkEventSink_Globals; 34 return *gGlobals; 35 } 36 37 SkEventSink::SkEventSink() : fTagHead(NULL) { 38 SkEventSink_Globals& globals = getGlobals(); 39 40 globals.fSinkMutex.acquire(); 41 42 fID = ++globals.fNextSinkID; 43 fNextSink = globals.fSinkHead; 44 globals.fSinkHead = this; 45 46 globals.fSinkMutex.release(); 47 } 48 49 SkEventSink::~SkEventSink() { 50 SkEventSink_Globals& globals = getGlobals(); 51 52 if (fTagHead) 53 SkTagList::DeleteAll(fTagHead); 54 55 globals.fSinkMutex.acquire(); 56 57 SkEventSink* sink = globals.fSinkHead; 58 SkEventSink* prev = NULL; 59 60 for (;;) { 61 SkEventSink* next = sink->fNextSink; 62 if (sink == this) { 63 if (prev) { 64 prev->fNextSink = next; 65 } else { 66 globals.fSinkHead = next; 67 } 68 break; 69 } 70 prev = sink; 71 sink = next; 72 } 73 globals.fSinkMutex.release(); 74 } 75 76 bool SkEventSink::doEvent(const SkEvent& evt) { 77 return this->onEvent(evt); 78 } 79 80 bool SkEventSink::doQuery(SkEvent* evt) { 81 SkASSERT(evt); 82 return this->onQuery(evt); 83 } 84 85 bool SkEventSink::onEvent(const SkEvent&) { 86 return false; 87 } 88 89 bool SkEventSink::onQuery(SkEvent*) { 90 return false; 91 } 92 93 /////////////////////////////////////////////////////////////////////////////// 94 95 SkTagList* SkEventSink::findTagList(U8CPU tag) const { 96 return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL; 97 } 98 99 void SkEventSink::addTagList(SkTagList* rec) { 100 SkASSERT(rec); 101 SkASSERT(fTagHead == NULL || SkTagList::Find(fTagHead, rec->fTag) == NULL); 102 103 rec->fNext = fTagHead; 104 fTagHead = rec; 105 } 106 107 void SkEventSink::removeTagList(U8CPU tag) { 108 if (fTagHead) { 109 SkTagList::DeleteTag(&fTagHead, tag); 110 } 111 } 112 113 /////////////////////////////////////////////////////////////////////////////// 114 115 struct SkListenersTagList : SkTagList { 116 SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList) 117 { 118 fExtra16 = SkToU16(count); 119 fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID)); 120 } 121 virtual ~SkListenersTagList() 122 { 123 sk_free(fIDs); 124 } 125 126 int countListners() const { return fExtra16; } 127 128 int find(SkEventSinkID id) const 129 { 130 const SkEventSinkID* idptr = fIDs; 131 for (int i = fExtra16 - 1; i >= 0; --i) 132 if (idptr[i] == id) 133 return i; 134 return -1; 135 } 136 137 SkEventSinkID* fIDs; 138 }; 139 140 void SkEventSink::addListenerID(SkEventSinkID id) 141 { 142 if (id == 0) 143 return; 144 145 SkListenersTagList* prev = (SkListenersTagList*)this->findTagList(kListeners_SkTagList); 146 int count = 0; 147 148 if (prev) 149 { 150 if (prev->find(id) >= 0) 151 return; 152 count = prev->countListners(); 153 } 154 155 SkListenersTagList* next = SkNEW_ARGS(SkListenersTagList, (count + 1)); 156 157 if (prev) 158 { 159 memcpy(next->fIDs, prev->fIDs, count * sizeof(SkEventSinkID)); 160 this->removeTagList(kListeners_SkTagList); 161 } 162 next->fIDs[count] = id; 163 this->addTagList(next); 164 } 165 166 void SkEventSink::copyListeners(const SkEventSink& sink) 167 { 168 SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList); 169 if (sinkList == NULL) 170 return; 171 SkASSERT(sinkList->countListners() > 0); 172 const SkEventSinkID* iter = sinkList->fIDs; 173 const SkEventSinkID* stop = iter + sinkList->countListners(); 174 while (iter < stop) 175 addListenerID(*iter++); 176 } 177 178 void SkEventSink::removeListenerID(SkEventSinkID id) 179 { 180 if (id == 0) 181 return; 182 183 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList); 184 185 if (list == NULL) 186 return; 187 188 int index = list->find(id); 189 if (index >= 0) 190 { 191 int count = list->countListners(); 192 SkASSERT(count > 0); 193 if (count == 1) 194 this->removeTagList(kListeners_SkTagList); 195 else 196 { 197 // overwrite without resize/reallocating our struct (for speed) 198 list->fIDs[index] = list->fIDs[count - 1]; 199 list->fExtra16 = SkToU16(count - 1); 200 } 201 } 202 } 203 204 bool SkEventSink::hasListeners() const 205 { 206 return this->findTagList(kListeners_SkTagList) != NULL; 207 } 208 209 void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay) { 210 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList); 211 if (list) { 212 SkASSERT(list->countListners() > 0); 213 const SkEventSinkID* iter = list->fIDs; 214 const SkEventSinkID* stop = iter + list->countListners(); 215 while (iter < stop) { 216 SkEvent* copy = SkNEW_ARGS(SkEvent, (evt)); 217 copy->setTargetID(*iter++)->postDelay(delay); 218 } 219 } 220 } 221 222 /////////////////////////////////////////////////////////////////////////////// 223 224 SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt) { 225 SkEvent::Proc proc = evt.getTargetProc(); 226 if (proc) { 227 return proc(evt) ? kHandled_EventResult : kNotHandled_EventResult; 228 } 229 230 SkEventSink* sink = SkEventSink::FindSink(evt.getTargetID()); 231 if (sink) { 232 return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult; 233 } 234 235 return kSinkNotFound_EventResult; 236 } 237 238 SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID) 239 { 240 if (sinkID == 0) 241 return 0; 242 243 SkEventSink_Globals& globals = getGlobals(); 244 SkAutoMutexAcquire ac(globals.fSinkMutex); 245 SkEventSink* sink = globals.fSinkHead; 246 247 while (sink) 248 { 249 if (sink->getSinkID() == sinkID) 250 return sink; 251 sink = sink->fNextSink; 252 } 253 return NULL; 254 } 255 256 //////////////////////////////////////////////////////////////////////////////////////// 257 //////////////////////////////////////////////////////////////////////////////////////// 258 259 #if 0 // experimental, not tested 260 261 #include "SkThread.h" 262 #include "SkTDict.h" 263 264 #define kMinStringBufferSize 128 265 SK_DECLARE_STATIC_MUTEX(gNamedSinkMutex); 266 static SkTDict<SkEventSinkID> gNamedSinkIDs(kMinStringBufferSize); 267 268 /** Register a name/id pair with the system. If the name already exists, 269 replace its ID with the new id. This pair will persist until UnregisterNamedSink() 270 is called. 271 */ 272 void SkEventSink::RegisterNamedSinkID(const char name[], SkEventSinkID id) 273 { 274 if (id && name && *name) 275 { 276 SkAutoMutexAcquire ac(gNamedSinkMutex); 277 gNamedSinkIDs.set(name, id); 278 } 279 } 280 281 /** Return the id that matches the specified name (from a previous call to 282 RegisterNamedSinkID(). If no match is found, return 0 283 */ 284 SkEventSinkID SkEventSink::FindNamedSinkID(const char name[]) 285 { 286 SkEventSinkID id = 0; 287 288 if (name && *name) 289 { 290 SkAutoMutexAcquire ac(gNamedSinkMutex); 291 (void)gNamedSinkIDs.find(name, &id); 292 } 293 return id; 294 } 295 296 /** Remove all name/id pairs from the system. This is call internally 297 on shutdown, to ensure no memory leaks. It should not be called 298 before shutdown. 299 */ 300 void SkEventSink::RemoveAllNamedSinkIDs() 301 { 302 SkAutoMutexAcquire ac(gNamedSinkMutex); 303 (void)gNamedSinkIDs.reset(); 304 } 305 #endif 306