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