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