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 17SK_DEFINE_INST_COUNT(SkEventSink) 18 19class SkEventSink_Globals { 20public: 21 SkEventSink_Globals() { 22 fNextSinkID = 0; 23 fSinkHead = NULL; 24 } 25 26 SkMutex fSinkMutex; 27 SkEventSinkID fNextSinkID; 28 SkEventSink* fSinkHead; 29}; 30 31static 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 37SkEventSink::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 49SkEventSink::~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 76bool SkEventSink::doEvent(const SkEvent& evt) { 77 return this->onEvent(evt); 78} 79 80bool SkEventSink::doQuery(SkEvent* evt) { 81 SkASSERT(evt); 82 return this->onQuery(evt); 83} 84 85bool SkEventSink::onEvent(const SkEvent&) { 86 return false; 87} 88 89bool SkEventSink::onQuery(SkEvent*) { 90 return false; 91} 92 93/////////////////////////////////////////////////////////////////////////////// 94 95SkTagList* SkEventSink::findTagList(U8CPU tag) const { 96 return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL; 97} 98 99void 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 107void SkEventSink::removeTagList(U8CPU tag) { 108 if (fTagHead) { 109 SkTagList::DeleteTag(&fTagHead, tag); 110 } 111} 112 113/////////////////////////////////////////////////////////////////////////////// 114 115struct 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 140void 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 166void 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 178void 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 204bool SkEventSink::hasListeners() const 205{ 206 return this->findTagList(kListeners_SkTagList) != NULL; 207} 208 209void 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 224SkEventSink::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 238SkEventSink* 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 265SK_DECLARE_STATIC_MUTEX(gNamedSinkMutex); 266static 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*/ 272void 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*/ 284SkEventSinkID 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*/ 300void SkEventSink::RemoveAllNamedSinkIDs() 301{ 302 SkAutoMutexAcquire ac(gNamedSinkMutex); 303 (void)gNamedSinkIDs.reset(); 304} 305#endif 306