• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SkEventSink_Globals()16     SkEventSink_Globals() {
17         fNextSinkID = 0;
18         fSinkHead = nullptr;
19     }
20 
21     SkMutex         fSinkMutex;
22     SkEventSinkID   fNextSinkID;
23     SkEventSink*    fSinkHead;
24 };
25 
getGlobals()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 
SkEventSink()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 
~SkEventSink()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 
doEvent(const SkEvent & evt)71 bool SkEventSink::doEvent(const SkEvent& evt) {
72     return this->onEvent(evt);
73 }
74 
doQuery(SkEvent * evt)75 bool SkEventSink::doQuery(SkEvent* evt) {
76     SkASSERT(evt);
77     return this->onQuery(evt);
78 }
79 
onEvent(const SkEvent &)80 bool SkEventSink::onEvent(const SkEvent&) {
81     return false;
82 }
83 
onQuery(SkEvent *)84 bool SkEventSink::onQuery(SkEvent*) {
85     return false;
86 }
87 
88 ///////////////////////////////////////////////////////////////////////////////
89 
findTagList(U8CPU tag) const90 SkTagList* SkEventSink::findTagList(U8CPU tag) const {
91     return fTagHead ? SkTagList::Find(fTagHead, tag) : nullptr;
92 }
93 
addTagList(SkTagList * rec)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 
removeTagList(U8CPU tag)102 void SkEventSink::removeTagList(U8CPU tag) {
103     if (fTagHead) {
104         SkTagList::DeleteTag(&fTagHead, tag);
105     }
106 }
107 
108 ///////////////////////////////////////////////////////////////////////////////
109 
110 struct SkListenersTagList : SkTagList {
SkListenersTagListSkListenersTagList111     SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
112     {
113         fExtra16 = SkToU16(count);
114         fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
115     }
~SkListenersTagListSkListenersTagList116     virtual ~SkListenersTagList()
117     {
118         sk_free(fIDs);
119     }
120 
countListnersSkListenersTagList121     int countListners() const { return fExtra16; }
122 
findSkListenersTagList123     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 
addListenerID(SkEventSinkID id)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 
copyListeners(const SkEventSink & sink)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 
removeListenerID(SkEventSinkID id)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 
hasListeners() const199 bool SkEventSink::hasListeners() const
200 {
201     return this->findTagList(kListeners_SkTagList) != nullptr;
202 }
203 
postToListeners(const SkEvent & evt,SkMSec delay)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 
DoEvent(const SkEvent & evt)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 
FindSink(SkEventSinkID sinkID)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