Home | History | Annotate | Download | only in views
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 
      9 #include "SkEventSink.h"
     10 #include "SkMutex.h"
     11 #include "SkTagList.h"
     12 #include "SkTime.h"
     13 
     14 class SkEventSink_Globals {
     15 public:
     16     SkEventSink_Globals() {
     17         fNextSinkID = 0;
     18         fSinkHead = nullptr;
     19     }
     20 
     21     SkMutex         fSinkMutex;
     22     SkEventSinkID   fNextSinkID;
     23     SkEventSink*    fSinkHead;
     24 };
     25 
     26 static SkEventSink_Globals& getGlobals() {
     27     // leak this, so we don't incur any shutdown perf hit
     28     static SkEventSink_Globals* gGlobals = new SkEventSink_Globals;
     29     return *gGlobals;
     30 }
     31 
     32 SkEventSink::SkEventSink() : fTagHead(nullptr) {
     33     SkEventSink_Globals& globals = getGlobals();
     34 
     35     globals.fSinkMutex.acquire();
     36 
     37     fID = ++globals.fNextSinkID;
     38     fNextSink = globals.fSinkHead;
     39     globals.fSinkHead = this;
     40 
     41     globals.fSinkMutex.release();
     42 }
     43 
     44 SkEventSink::~SkEventSink() {
     45     SkEventSink_Globals& globals = getGlobals();
     46 
     47     if (fTagHead)
     48         SkTagList::DeleteAll(fTagHead);
     49 
     50     globals.fSinkMutex.acquire();
     51 
     52     SkEventSink* sink = globals.fSinkHead;
     53     SkEventSink* prev = nullptr;
     54 
     55     for (;;) {
     56         SkEventSink* next = sink->fNextSink;
     57         if (sink == this) {
     58             if (prev) {
     59                 prev->fNextSink = next;
     60             } else {
     61                 globals.fSinkHead = next;
     62             }
     63             break;
     64         }
     65         prev = sink;
     66         sink = next;
     67     }
     68     globals.fSinkMutex.release();
     69 }
     70 
     71 bool SkEventSink::doEvent(const SkEvent& evt) {
     72     return this->onEvent(evt);
     73 }
     74 
     75 bool SkEventSink::doQuery(SkEvent* evt) {
     76     SkASSERT(evt);
     77     return this->onQuery(evt);
     78 }
     79 
     80 bool SkEventSink::onEvent(const SkEvent&) {
     81     return false;
     82 }
     83 
     84 bool SkEventSink::onQuery(SkEvent*) {
     85     return false;
     86 }
     87 
     88 ///////////////////////////////////////////////////////////////////////////////
     89 
     90 SkTagList* SkEventSink::findTagList(U8CPU tag) const {
     91     return fTagHead ? SkTagList::Find(fTagHead, tag) : nullptr;
     92 }
     93 
     94 void SkEventSink::addTagList(SkTagList* rec) {
     95     SkASSERT(rec);
     96     SkASSERT(fTagHead == nullptr || SkTagList::Find(fTagHead, rec->fTag) == nullptr);
     97 
     98     rec->fNext = fTagHead;
     99     fTagHead = rec;
    100 }
    101 
    102 void SkEventSink::removeTagList(U8CPU tag) {
    103     if (fTagHead) {
    104         SkTagList::DeleteTag(&fTagHead, tag);
    105     }
    106 }
    107 
    108 ///////////////////////////////////////////////////////////////////////////////
    109 
    110 struct SkListenersTagList : SkTagList {
    111     SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
    112     {
    113         fExtra16 = SkToU16(count);
    114         fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
    115     }
    116     virtual ~SkListenersTagList()
    117     {
    118         sk_free(fIDs);
    119     }
    120 
    121     int countListners() const { return fExtra16; }
    122 
    123     int find(SkEventSinkID id) const
    124     {
    125         const SkEventSinkID* idptr = fIDs;
    126         for (int i = fExtra16 - 1; i >= 0; --i)
    127             if (idptr[i] == id)
    128                 return i;
    129         return -1;
    130     }
    131 
    132     SkEventSinkID*  fIDs;
    133 };
    134 
    135 void SkEventSink::addListenerID(SkEventSinkID id)
    136 {
    137     if (id == 0)
    138         return;
    139 
    140     SkListenersTagList* prev = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
    141     int                 count = 0;
    142 
    143     if (prev)
    144     {
    145         if (prev->find(id) >= 0)
    146             return;
    147         count = prev->countListners();
    148     }
    149 
    150     SkListenersTagList* next = new SkListenersTagList(count + 1);
    151 
    152     if (prev)
    153     {
    154         memcpy(next->fIDs, prev->fIDs, count * sizeof(SkEventSinkID));
    155         this->removeTagList(kListeners_SkTagList);
    156     }
    157     next->fIDs[count] = id;
    158     this->addTagList(next);
    159 }
    160 
    161 void SkEventSink::copyListeners(const SkEventSink& sink)
    162 {
    163     SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList);
    164     if (sinkList == nullptr)
    165         return;
    166     SkASSERT(sinkList->countListners() > 0);
    167     const SkEventSinkID* iter = sinkList->fIDs;
    168     const SkEventSinkID* stop = iter + sinkList->countListners();
    169     while (iter < stop)
    170         addListenerID(*iter++);
    171 }
    172 
    173 void SkEventSink::removeListenerID(SkEventSinkID id)
    174 {
    175     if (id == 0)
    176         return;
    177 
    178     SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
    179 
    180     if (list == nullptr)
    181         return;
    182 
    183     int index = list->find(id);
    184     if (index >= 0)
    185     {
    186         int count = list->countListners();
    187         SkASSERT(count > 0);
    188         if (count == 1)
    189             this->removeTagList(kListeners_SkTagList);
    190         else
    191         {
    192             // overwrite without resize/reallocating our struct (for speed)
    193             list->fIDs[index] = list->fIDs[count - 1];
    194             list->fExtra16 = SkToU16(count - 1);
    195         }
    196     }
    197 }
    198 
    199 bool SkEventSink::hasListeners() const
    200 {
    201     return this->findTagList(kListeners_SkTagList) != nullptr;
    202 }
    203 
    204 void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay) {
    205     SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
    206     if (list) {
    207         SkASSERT(list->countListners() > 0);
    208         const SkEventSinkID* iter = list->fIDs;
    209         const SkEventSinkID* stop = iter + list->countListners();
    210         while (iter < stop) {
    211             SkEvent* copy = new SkEvent(evt);
    212             copy->setTargetID(*iter++)->postDelay(delay);
    213         }
    214     }
    215 }
    216 
    217 ///////////////////////////////////////////////////////////////////////////////
    218 
    219 SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt) {
    220     SkEvent::Proc proc = evt.getTargetProc();
    221     if (proc) {
    222         return proc(evt) ? kHandled_EventResult : kNotHandled_EventResult;
    223     }
    224 
    225     SkEventSink* sink = SkEventSink::FindSink(evt.getTargetID());
    226     if (sink) {
    227         return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
    228     }
    229 
    230     return kSinkNotFound_EventResult;
    231 }
    232 
    233 SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
    234 {
    235     if (sinkID == 0)
    236         return 0;
    237 
    238     SkEventSink_Globals&    globals = getGlobals();
    239     SkAutoMutexAcquire      ac(globals.fSinkMutex);
    240     SkEventSink*            sink = globals.fSinkHead;
    241 
    242     while (sink)
    243     {
    244         if (sink->getSinkID() == sinkID)
    245             return sink;
    246         sink = sink->fNextSink;
    247     }
    248     return nullptr;
    249 }
    250