• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SkEventSink_Globals()19     SkEventSink_Globals() {
20         fNextSinkID = 0;
21         fSinkHead = NULL;
22     }
23 
24     SkMutex         fSinkMutex;
25     SkEventSinkID   fNextSinkID;
26     SkEventSink*    fSinkHead;
27 };
28 
getGlobals()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 
SkEventSink()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 
~SkEventSink()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 
doEvent(const SkEvent & evt)74 bool SkEventSink::doEvent(const SkEvent& evt) {
75     return this->onEvent(evt);
76 }
77 
doQuery(SkEvent * evt)78 bool SkEventSink::doQuery(SkEvent* evt) {
79     SkASSERT(evt);
80     return this->onQuery(evt);
81 }
82 
onEvent(const SkEvent &)83 bool SkEventSink::onEvent(const SkEvent&) {
84     return false;
85 }
86 
onQuery(SkEvent *)87 bool SkEventSink::onQuery(SkEvent*) {
88     return false;
89 }
90 
91 ///////////////////////////////////////////////////////////////////////////////
92 
findTagList(U8CPU tag) const93 SkTagList* SkEventSink::findTagList(U8CPU tag) const {
94     return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL;
95 }
96 
addTagList(SkTagList * rec)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 
removeTagList(U8CPU tag)105 void SkEventSink::removeTagList(U8CPU tag) {
106     if (fTagHead) {
107         SkTagList::DeleteTag(&fTagHead, tag);
108     }
109 }
110 
111 ///////////////////////////////////////////////////////////////////////////////
112 
113 struct SkListenersTagList : SkTagList {
SkListenersTagListSkListenersTagList114     SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
115     {
116         fExtra16 = SkToU16(count);
117         fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
118     }
~SkListenersTagListSkListenersTagList119     virtual ~SkListenersTagList()
120     {
121         sk_free(fIDs);
122     }
123 
countListnersSkListenersTagList124     int countListners() const { return fExtra16; }
125 
findSkListenersTagList126     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 
addListenerID(SkEventSinkID id)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 
copyListeners(const SkEventSink & sink)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 
removeListenerID(SkEventSinkID id)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 
hasListeners() const202 bool SkEventSink::hasListeners() const
203 {
204     return this->findTagList(kListeners_SkTagList) != NULL;
205 }
206 
postToListeners(const SkEvent & evt,SkMSec delay)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 
DoEvent(const SkEvent & evt)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 
FindSink(SkEventSinkID sinkID)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