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 "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