michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkEventSink.h" michael@0: #include "SkTagList.h" michael@0: #include "SkThread.h" michael@0: michael@0: #include "SkThread.h" michael@0: #include "SkTime.h" michael@0: michael@0: class SkEventSink_Globals { michael@0: public: michael@0: SkEventSink_Globals() { michael@0: fNextSinkID = 0; michael@0: fSinkHead = NULL; michael@0: } michael@0: michael@0: SkMutex fSinkMutex; michael@0: SkEventSinkID fNextSinkID; michael@0: SkEventSink* fSinkHead; michael@0: }; michael@0: michael@0: static SkEventSink_Globals& getGlobals() { michael@0: // leak this, so we don't incur any shutdown perf hit michael@0: static SkEventSink_Globals* gGlobals = new SkEventSink_Globals; michael@0: return *gGlobals; michael@0: } michael@0: michael@0: SkEventSink::SkEventSink() : fTagHead(NULL) { michael@0: SkEventSink_Globals& globals = getGlobals(); michael@0: michael@0: globals.fSinkMutex.acquire(); michael@0: michael@0: fID = ++globals.fNextSinkID; michael@0: fNextSink = globals.fSinkHead; michael@0: globals.fSinkHead = this; michael@0: michael@0: globals.fSinkMutex.release(); michael@0: } michael@0: michael@0: SkEventSink::~SkEventSink() { michael@0: SkEventSink_Globals& globals = getGlobals(); michael@0: michael@0: if (fTagHead) michael@0: SkTagList::DeleteAll(fTagHead); michael@0: michael@0: globals.fSinkMutex.acquire(); michael@0: michael@0: SkEventSink* sink = globals.fSinkHead; michael@0: SkEventSink* prev = NULL; michael@0: michael@0: for (;;) { michael@0: SkEventSink* next = sink->fNextSink; michael@0: if (sink == this) { michael@0: if (prev) { michael@0: prev->fNextSink = next; michael@0: } else { michael@0: globals.fSinkHead = next; michael@0: } michael@0: break; michael@0: } michael@0: prev = sink; michael@0: sink = next; michael@0: } michael@0: globals.fSinkMutex.release(); michael@0: } michael@0: michael@0: bool SkEventSink::doEvent(const SkEvent& evt) { michael@0: return this->onEvent(evt); michael@0: } michael@0: michael@0: bool SkEventSink::doQuery(SkEvent* evt) { michael@0: SkASSERT(evt); michael@0: return this->onQuery(evt); michael@0: } michael@0: michael@0: bool SkEventSink::onEvent(const SkEvent&) { michael@0: return false; michael@0: } michael@0: michael@0: bool SkEventSink::onQuery(SkEvent*) { michael@0: return false; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkTagList* SkEventSink::findTagList(U8CPU tag) const { michael@0: return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL; michael@0: } michael@0: michael@0: void SkEventSink::addTagList(SkTagList* rec) { michael@0: SkASSERT(rec); michael@0: SkASSERT(fTagHead == NULL || SkTagList::Find(fTagHead, rec->fTag) == NULL); michael@0: michael@0: rec->fNext = fTagHead; michael@0: fTagHead = rec; michael@0: } michael@0: michael@0: void SkEventSink::removeTagList(U8CPU tag) { michael@0: if (fTagHead) { michael@0: SkTagList::DeleteTag(&fTagHead, tag); michael@0: } michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: struct SkListenersTagList : SkTagList { michael@0: SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList) michael@0: { michael@0: fExtra16 = SkToU16(count); michael@0: fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID)); michael@0: } michael@0: virtual ~SkListenersTagList() michael@0: { michael@0: sk_free(fIDs); michael@0: } michael@0: michael@0: int countListners() const { return fExtra16; } michael@0: michael@0: int find(SkEventSinkID id) const michael@0: { michael@0: const SkEventSinkID* idptr = fIDs; michael@0: for (int i = fExtra16 - 1; i >= 0; --i) michael@0: if (idptr[i] == id) michael@0: return i; michael@0: return -1; michael@0: } michael@0: michael@0: SkEventSinkID* fIDs; michael@0: }; michael@0: michael@0: void SkEventSink::addListenerID(SkEventSinkID id) michael@0: { michael@0: if (id == 0) michael@0: return; michael@0: michael@0: SkListenersTagList* prev = (SkListenersTagList*)this->findTagList(kListeners_SkTagList); michael@0: int count = 0; michael@0: michael@0: if (prev) michael@0: { michael@0: if (prev->find(id) >= 0) michael@0: return; michael@0: count = prev->countListners(); michael@0: } michael@0: michael@0: SkListenersTagList* next = SkNEW_ARGS(SkListenersTagList, (count + 1)); michael@0: michael@0: if (prev) michael@0: { michael@0: memcpy(next->fIDs, prev->fIDs, count * sizeof(SkEventSinkID)); michael@0: this->removeTagList(kListeners_SkTagList); michael@0: } michael@0: next->fIDs[count] = id; michael@0: this->addTagList(next); michael@0: } michael@0: michael@0: void SkEventSink::copyListeners(const SkEventSink& sink) michael@0: { michael@0: SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList); michael@0: if (sinkList == NULL) michael@0: return; michael@0: SkASSERT(sinkList->countListners() > 0); michael@0: const SkEventSinkID* iter = sinkList->fIDs; michael@0: const SkEventSinkID* stop = iter + sinkList->countListners(); michael@0: while (iter < stop) michael@0: addListenerID(*iter++); michael@0: } michael@0: michael@0: void SkEventSink::removeListenerID(SkEventSinkID id) michael@0: { michael@0: if (id == 0) michael@0: return; michael@0: michael@0: SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList); michael@0: michael@0: if (list == NULL) michael@0: return; michael@0: michael@0: int index = list->find(id); michael@0: if (index >= 0) michael@0: { michael@0: int count = list->countListners(); michael@0: SkASSERT(count > 0); michael@0: if (count == 1) michael@0: this->removeTagList(kListeners_SkTagList); michael@0: else michael@0: { michael@0: // overwrite without resize/reallocating our struct (for speed) michael@0: list->fIDs[index] = list->fIDs[count - 1]; michael@0: list->fExtra16 = SkToU16(count - 1); michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool SkEventSink::hasListeners() const michael@0: { michael@0: return this->findTagList(kListeners_SkTagList) != NULL; michael@0: } michael@0: michael@0: void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay) { michael@0: SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList); michael@0: if (list) { michael@0: SkASSERT(list->countListners() > 0); michael@0: const SkEventSinkID* iter = list->fIDs; michael@0: const SkEventSinkID* stop = iter + list->countListners(); michael@0: while (iter < stop) { michael@0: SkEvent* copy = SkNEW_ARGS(SkEvent, (evt)); michael@0: copy->setTargetID(*iter++)->postDelay(delay); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt) { michael@0: SkEvent::Proc proc = evt.getTargetProc(); michael@0: if (proc) { michael@0: return proc(evt) ? kHandled_EventResult : kNotHandled_EventResult; michael@0: } michael@0: michael@0: SkEventSink* sink = SkEventSink::FindSink(evt.getTargetID()); michael@0: if (sink) { michael@0: return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult; michael@0: } michael@0: michael@0: return kSinkNotFound_EventResult; michael@0: } michael@0: michael@0: SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID) michael@0: { michael@0: if (sinkID == 0) michael@0: return 0; michael@0: michael@0: SkEventSink_Globals& globals = getGlobals(); michael@0: SkAutoMutexAcquire ac(globals.fSinkMutex); michael@0: SkEventSink* sink = globals.fSinkHead; michael@0: michael@0: while (sink) michael@0: { michael@0: if (sink->getSinkID() == sinkID) michael@0: return sink; michael@0: sink = sink->fNextSink; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////////////// michael@0: //////////////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #if 0 // experimental, not tested michael@0: michael@0: #include "SkThread.h" michael@0: #include "SkTDict.h" michael@0: michael@0: #define kMinStringBufferSize 128 michael@0: SK_DECLARE_STATIC_MUTEX(gNamedSinkMutex); michael@0: static SkTDict gNamedSinkIDs(kMinStringBufferSize); michael@0: michael@0: /** Register a name/id pair with the system. If the name already exists, michael@0: replace its ID with the new id. This pair will persist until UnregisterNamedSink() michael@0: is called. michael@0: */ michael@0: void SkEventSink::RegisterNamedSinkID(const char name[], SkEventSinkID id) michael@0: { michael@0: if (id && name && *name) michael@0: { michael@0: SkAutoMutexAcquire ac(gNamedSinkMutex); michael@0: gNamedSinkIDs.set(name, id); michael@0: } michael@0: } michael@0: michael@0: /** Return the id that matches the specified name (from a previous call to michael@0: RegisterNamedSinkID(). If no match is found, return 0 michael@0: */ michael@0: SkEventSinkID SkEventSink::FindNamedSinkID(const char name[]) michael@0: { michael@0: SkEventSinkID id = 0; michael@0: michael@0: if (name && *name) michael@0: { michael@0: SkAutoMutexAcquire ac(gNamedSinkMutex); michael@0: (void)gNamedSinkIDs.find(name, &id); michael@0: } michael@0: return id; michael@0: } michael@0: michael@0: /** Remove all name/id pairs from the system. This is call internally michael@0: on shutdown, to ensure no memory leaks. It should not be called michael@0: before shutdown. michael@0: */ michael@0: void SkEventSink::RemoveAllNamedSinkIDs() michael@0: { michael@0: SkAutoMutexAcquire ac(gNamedSinkMutex); michael@0: (void)gNamedSinkIDs.reset(); michael@0: } michael@0: #endif