blob: 3c3aa5d213157cde54d005e8c9880b21a2c888e5 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkEventSink.h"
11#include "SkTagList.h"
12#include "SkThread.h"
13
14#include "SkGlobals.h"
15#include "SkThread.h"
16#include "SkTime.h"
17
18#define SK_EventSink_GlobalsTag SkSetFourByteTag('e', 'v', 's', 'k')
19
20class SkEventSink_Globals : public SkGlobals::Rec {
21public:
22 SkMutex fSinkMutex;
23 SkEventSinkID fNextSinkID;
24 SkEventSink* fSinkHead;
25};
26
27static SkGlobals::Rec* create_globals()
28{
29 SkEventSink_Globals* rec = new SkEventSink_Globals;
30 rec->fNextSinkID = 0;
31 rec->fSinkHead = NULL;
32 return rec;
33}
34
35SkEventSink::SkEventSink() : fTagHead(NULL)
36{
37 SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
38
39 globals.fSinkMutex.acquire();
40
41 fID = ++globals.fNextSinkID;
42 fNextSink = globals.fSinkHead;
43 globals.fSinkHead = this;
44
45 globals.fSinkMutex.release();
46}
47
48SkEventSink::~SkEventSink()
49{
50 SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
51
52 if (fTagHead)
53 SkTagList::DeleteAll(fTagHead);
54
55 globals.fSinkMutex.acquire();
56
57 SkEventSink* sink = globals.fSinkHead;
58 SkEventSink* prev = NULL;
59
60 for (;;)
61 {
62 SkEventSink* next = sink->fNextSink;
63 if (sink == this)
64 {
65 if (prev)
66 prev->fNextSink = next;
67 else
68 globals.fSinkHead = next;
69 break;
70 }
71 prev = sink;
72 sink = next;
73 }
74 globals.fSinkMutex.release();
75}
76
77bool SkEventSink::doEvent(const SkEvent& evt)
78{
79 return this->onEvent(evt);
80}
81
82bool SkEventSink::doQuery(SkEvent* evt)
83{
84 SkASSERT(evt);
85 return this->onQuery(evt);
86}
87
88bool SkEventSink::onEvent(const SkEvent&)
89{
90 return false;
91}
92
93bool SkEventSink::onQuery(SkEvent*)
94{
95 return false;
96}
97
98///////////////////////////////////////////////////////////////////////////////
99
100SkTagList* SkEventSink::findTagList(U8CPU tag) const
101{
102 return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL;
103}
104
105void SkEventSink::addTagList(SkTagList* rec)
106{
107 SkASSERT(rec);
108 SkASSERT(fTagHead == NULL || SkTagList::Find(fTagHead, rec->fTag) == NULL);
109
110 rec->fNext = fTagHead;
111 fTagHead = rec;
112}
113
114void SkEventSink::removeTagList(U8CPU tag)
115{
116 if (fTagHead)
117 SkTagList::DeleteTag(&fTagHead, tag);
118}
119
120///////////////////////////////////////////////////////////////////////////////
121
122struct SkListenersTagList : SkTagList {
123 SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
124 {
125 fExtra16 = SkToU16(count);
126 fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
127 }
128 virtual ~SkListenersTagList()
129 {
130 sk_free(fIDs);
131 }
132
133 int countListners() const { return fExtra16; }
134
135 int find(SkEventSinkID id) const
136 {
137 const SkEventSinkID* idptr = fIDs;
138 for (int i = fExtra16 - 1; i >= 0; --i)
139 if (idptr[i] == id)
140 return i;
141 return -1;
142 }
143
144 SkEventSinkID* fIDs;
145};
146
147void SkEventSink::addListenerID(SkEventSinkID id)
148{
149 if (id == 0)
150 return;
151
152 SkListenersTagList* prev = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
153 int count = 0;
154
155 if (prev)
156 {
157 if (prev->find(id) >= 0)
158 return;
159 count = prev->countListners();
160 }
161
162 SkListenersTagList* next = SkNEW_ARGS(SkListenersTagList, (count + 1));
163
164 if (prev)
165 {
166 memcpy(next->fIDs, prev->fIDs, count * sizeof(SkEventSinkID));
167 this->removeTagList(kListeners_SkTagList);
168 }
169 next->fIDs[count] = id;
170 this->addTagList(next);
171}
172
173void SkEventSink::copyListeners(const SkEventSink& sink)
174{
175 SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList);
176 if (sinkList == NULL)
177 return;
178 SkASSERT(sinkList->countListners() > 0);
179 const SkEventSinkID* iter = sinkList->fIDs;
180 const SkEventSinkID* stop = iter + sinkList->countListners();
181 while (iter < stop)
182 addListenerID(*iter++);
183}
184
185void SkEventSink::removeListenerID(SkEventSinkID id)
186{
187 if (id == 0)
188 return;
189
190 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
191
192 if (list == NULL)
193 return;
194
195 int index = list->find(id);
196 if (index >= 0)
197 {
198 int count = list->countListners();
199 SkASSERT(count > 0);
200 if (count == 1)
201 this->removeTagList(kListeners_SkTagList);
202 else
203 {
204 // overwrite without resize/reallocating our struct (for speed)
205 list->fIDs[index] = list->fIDs[count - 1];
206 list->fExtra16 = SkToU16(count - 1);
207 }
208 }
209}
210
211bool SkEventSink::hasListeners() const
212{
213 return this->findTagList(kListeners_SkTagList) != NULL;
214}
215
216void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay)
217{
218 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
219 if (list)
220 {
221 SkASSERT(list->countListners() > 0);
222 const SkEventSinkID* iter = list->fIDs;
223 const SkEventSinkID* stop = iter + list->countListners();
224 while (iter < stop)
225 (SkNEW_ARGS(SkEvent, (evt)))->post(*iter++, delay);
226 }
227}
228
229///////////////////////////////////////////////////////////////////////////////
230
231SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt, SkEventSinkID sinkID)
232{
233 SkEventSink* sink = SkEventSink::FindSink(sinkID);
234
235 if (sink)
236 {
237#ifdef SK_DEBUG
238 if (evt.isDebugTrace())
239 {
240 SkString etype;
241 evt.getType(&etype);
242 SkDebugf("SkEventTrace: dispatching event <%s> to 0x%x", etype.c_str(), sinkID);
243 const char* idStr = evt.findString("id");
244 if (idStr)
245 SkDebugf(" (%s)", idStr);
246 SkDebugf("\n");
247 }
248#endif
249 return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
250 }
251 else
252 {
253#ifdef SK_DEBUG
254 if (sinkID)
255 SkDebugf("DoEvent: Can't find sink for ID(%x)\n", sinkID);
256 else
257 SkDebugf("Event sent to 0 sinkID\n");
258
259 if (evt.isDebugTrace())
260 {
261 SkString etype;
262 evt.getType(&etype);
263 SkDebugf("SkEventTrace: eventsink not found <%s> for 0x%x\n", etype.c_str(), sinkID);
264 }
265#endif
266 return kSinkNotFound_EventResult;
267 }
268}
269
270SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
271{
272 if (sinkID == 0)
273 return 0;
274
275 SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
276 SkAutoMutexAcquire ac(globals.fSinkMutex);
277 SkEventSink* sink = globals.fSinkHead;
278
279 while (sink)
280 {
281 if (sink->getSinkID() == sinkID)
282 return sink;
283 sink = sink->fNextSink;
284 }
285 return NULL;
286}
287
288////////////////////////////////////////////////////////////////////////////////////////
289////////////////////////////////////////////////////////////////////////////////////////
290
291#if 0 // experimental, not tested
292
293#include "SkThread.h"
294#include "SkTDict.h"
295
296#define kMinStringBufferSize 128
297static SkMutex gNamedSinkMutex;
298static SkTDict<SkEventSinkID> gNamedSinkIDs(kMinStringBufferSize);
299
300/** Register a name/id pair with the system. If the name already exists,
301 replace its ID with the new id. This pair will persist until UnregisterNamedSink()
302 is called.
303*/
304void SkEventSink::RegisterNamedSinkID(const char name[], SkEventSinkID id)
305{
306 if (id && name && *name)
307 {
308 SkAutoMutexAcquire ac(gNamedSinkMutex);
309 gNamedSinkIDs.set(name, id);
310 }
311}
312
313/** Return the id that matches the specified name (from a previous call to
314 RegisterNamedSinkID(). If no match is found, return 0
315*/
316SkEventSinkID SkEventSink::FindNamedSinkID(const char name[])
317{
318 SkEventSinkID id = 0;
319
320 if (name && *name)
321 {
322 SkAutoMutexAcquire ac(gNamedSinkMutex);
323 (void)gNamedSinkIDs.find(name, &id);
324 }
325 return id;
326}
327
328/** Remove all name/id pairs from the system. This is call internally
329 on shutdown, to ensure no memory leaks. It should not be called
330 before shutdown.
331*/
332void SkEventSink::RemoveAllNamedSinkIDs()
333{
334 SkAutoMutexAcquire ac(gNamedSinkMutex);
335 (void)gNamedSinkIDs.reset();
336}
337#endif