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