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 class SkEventSink_Globals { 18 public: 19 SkEventSink_Globals() { 20 fNextSinkID = 0; 21 fSinkHead = NULL; 22 } 23 24 SkMutex fSinkMutex; 25 SkEventSinkID fNextSinkID; 26 SkEventSink* fSinkHead; 27 }; 28 29 static 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 35 SkEventSink::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 47 SkEventSink::~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 74 bool SkEventSink::doEvent(const SkEvent& evt) { 75 return this->onEvent(evt); 76 } 77 78 bool SkEventSink::doQuery(SkEvent* evt) { 79 SkASSERT(evt); 80 return this->onQuery(evt); 81 } 82 83 bool SkEventSink::onEvent(const SkEvent&) { 84 return false; 85 } 86 87 bool SkEventSink::onQuery(SkEvent*) { 88 return false; 89 } 90 91 /////////////////////////////////////////////////////////////////////////////// 92 93 SkTagList* SkEventSink::findTagList(U8CPU tag) const { 94 return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL; 95 } 96 97 void 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 105 void SkEventSink::removeTagList(U8CPU tag) { 106 if (fTagHead) { 107 SkTagList::DeleteTag(&fTagHead, tag); 108 } 109 } 110 111 /////////////////////////////////////////////////////////////////////////////// 112 113 struct 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 138 void 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 164 void 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 176 void 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 202 bool SkEventSink::hasListeners() const 203 { 204 return this->findTagList(kListeners_SkTagList) != NULL; 205 } 206 207 void 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 222 SkEventSink::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 236 SkEventSink* 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 263 SK_DECLARE_STATIC_MUTEX(gNamedSinkMutex); 264 static 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 */ 270 void 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 */ 282 SkEventSinkID 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 */ 298 void SkEventSink::RemoveAllNamedSinkIDs() 299 { 300 SkAutoMutexAcquire ac(gNamedSinkMutex); 301 (void)gNamedSinkIDs.reset(); 302 } 303 #endif 304