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 15 class SkEventSink_Globals { 16 public: 17 SkEventSink_Globals() { 18 fNextSinkID = 0; 19 fSinkHead = nullptr; 20 } 21 22 SkMutex fSinkMutex; 23 SkEventSinkID fNextSinkID; 24 SkEventSink* fSinkHead; 25 }; 26 27 static 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 33 SkEventSink::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 45 SkEventSink::~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 72 bool SkEventSink::doEvent(const SkEvent& evt) { 73 return this->onEvent(evt); 74 } 75 76 bool SkEventSink::doQuery(SkEvent* evt) { 77 SkASSERT(evt); 78 return this->onQuery(evt); 79 } 80 81 bool SkEventSink::onEvent(const SkEvent&) { 82 return false; 83 } 84 85 bool SkEventSink::onQuery(SkEvent*) { 86 return false; 87 } 88 89 /////////////////////////////////////////////////////////////////////////////// 90 91 SkTagList* SkEventSink::findTagList(U8CPU tag) const { 92 return fTagHead ? SkTagList::Find(fTagHead, tag) : nullptr; 93 } 94 95 void 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 103 void SkEventSink::removeTagList(U8CPU tag) { 104 if (fTagHead) { 105 SkTagList::DeleteTag(&fTagHead, tag); 106 } 107 } 108 109 /////////////////////////////////////////////////////////////////////////////// 110 111 struct 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 136 void 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 162 void 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 174 void 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 200 bool SkEventSink::hasListeners() const 201 { 202 return this->findTagList(kListeners_SkTagList) != nullptr; 203 } 204 205 void 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 220 SkEventSink::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 234 SkEventSink* 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 261 SK_DECLARE_STATIC_MUTEX(gNamedSinkMutex); 262 static 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 */ 268 void 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 */ 280 SkEventSinkID 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 */ 296 void SkEventSink::RemoveAllNamedSinkIDs() 297 { 298 SkAutoMutexAcquire ac(gNamedSinkMutex); 299 (void)gNamedSinkIDs.reset(); 300 } 301 #endif 302