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:
SkEventSink_Globals()17     SkEventSink_Globals() {
18         fNextSinkID = 0;
19         fSinkHead = nullptr;
20     }
21 
22     SkMutex         fSinkMutex;
23     SkEventSinkID   fNextSinkID;
24     SkEventSink*    fSinkHead;
25 };
26 
getGlobals()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 
SkEventSink()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 
~SkEventSink()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 
doEvent(const SkEvent & evt)72 bool SkEventSink::doEvent(const SkEvent& evt) {
73     return this->onEvent(evt);
74 }
75 
doQuery(SkEvent * evt)76 bool SkEventSink::doQuery(SkEvent* evt) {
77     SkASSERT(evt);
78     return this->onQuery(evt);
79 }
80 
onEvent(const SkEvent &)81 bool SkEventSink::onEvent(const SkEvent&) {
82     return false;
83 }
84 
onQuery(SkEvent *)85 bool SkEventSink::onQuery(SkEvent*) {
86     return false;
87 }
88 
89 ///////////////////////////////////////////////////////////////////////////////
90 
findTagList(U8CPU tag) const91 SkTagList* SkEventSink::findTagList(U8CPU tag) const {
92     return fTagHead ? SkTagList::Find(fTagHead, tag) : nullptr;
93 }
94 
addTagList(SkTagList * rec)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 
removeTagList(U8CPU tag)103 void SkEventSink::removeTagList(U8CPU tag) {
104     if (fTagHead) {
105         SkTagList::DeleteTag(&fTagHead, tag);
106     }
107 }
108 
109 ///////////////////////////////////////////////////////////////////////////////
110 
111 struct SkListenersTagList : SkTagList {
SkListenersTagListSkListenersTagList112     SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
113     {
114         fExtra16 = SkToU16(count);
115         fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
116     }
~SkListenersTagListSkListenersTagList117     virtual ~SkListenersTagList()
118     {
119         sk_free(fIDs);
120     }
121 
countListnersSkListenersTagList122     int countListners() const { return fExtra16; }
123 
findSkListenersTagList124     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 
addListenerID(SkEventSinkID id)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 
copyListeners(const SkEventSink & sink)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 
removeListenerID(SkEventSinkID id)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 
hasListeners() const200 bool SkEventSink::hasListeners() const
201 {
202     return this->findTagList(kListeners_SkTagList) != nullptr;
203 }
204 
postToListeners(const SkEvent & evt,SkMSec delay)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 
DoEvent(const SkEvent & evt)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 
FindSink(SkEventSinkID sinkID)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