Home | History | Annotate | Download | only in views
      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