blob: 8f39156c51e959dccb0e18880d0c233c0d8023e6 [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
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkThread.h"
15#include "SkTime.h"
16
robertphillips@google.coma22e2112012-08-16 14:58:06 +000017SK_DEFINE_INST_COUNT(SkEventSink)
18
reed@google.com9998c662011-11-17 22:09:47 +000019class SkEventSink_Globals {
reed@android.com8a1c16f2008-12-17 15:59:43 +000020public:
reed@google.com9998c662011-11-17 22:09:47 +000021 SkEventSink_Globals() {
22 fNextSinkID = 0;
23 fSinkHead = NULL;
24 }
25
reed@android.com8a1c16f2008-12-17 15:59:43 +000026 SkMutex fSinkMutex;
27 SkEventSinkID fNextSinkID;
28 SkEventSink* fSinkHead;
29};
30
reed@google.com9998c662011-11-17 22:09:47 +000031static SkEventSink_Globals& getGlobals() {
32 // leak this, so we don't incur any shutdown perf hit
33 static SkEventSink_Globals* gGlobals = new SkEventSink_Globals;
34 return *gGlobals;
reed@android.com8a1c16f2008-12-17 15:59:43 +000035}
36
reed@google.com9998c662011-11-17 22:09:47 +000037SkEventSink::SkEventSink() : fTagHead(NULL) {
38 SkEventSink_Globals& globals = getGlobals();
reed@android.com8a1c16f2008-12-17 15:59:43 +000039
40 globals.fSinkMutex.acquire();
41
42 fID = ++globals.fNextSinkID;
43 fNextSink = globals.fSinkHead;
44 globals.fSinkHead = this;
45
46 globals.fSinkMutex.release();
47}
48
reed@google.com9998c662011-11-17 22:09:47 +000049SkEventSink::~SkEventSink() {
50 SkEventSink_Globals& globals = getGlobals();
reed@android.com8a1c16f2008-12-17 15:59:43 +000051
52 if (fTagHead)
53 SkTagList::DeleteAll(fTagHead);
54
55 globals.fSinkMutex.acquire();
56
57 SkEventSink* sink = globals.fSinkHead;
58 SkEventSink* prev = NULL;
59
reed@google.com9998c662011-11-17 22:09:47 +000060 for (;;) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 SkEventSink* next = sink->fNextSink;
reed@google.com9998c662011-11-17 22:09:47 +000062 if (sink == this) {
63 if (prev) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 prev->fNextSink = next;
reed@google.com9998c662011-11-17 22:09:47 +000065 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 globals.fSinkHead = next;
reed@google.com9998c662011-11-17 22:09:47 +000067 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000068 break;
69 }
70 prev = sink;
71 sink = next;
72 }
73 globals.fSinkMutex.release();
74}
75
reed@google.com9998c662011-11-17 22:09:47 +000076bool SkEventSink::doEvent(const SkEvent& evt) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000077 return this->onEvent(evt);
78}
79
reed@google.com9998c662011-11-17 22:09:47 +000080bool SkEventSink::doQuery(SkEvent* evt) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 SkASSERT(evt);
82 return this->onQuery(evt);
83}
84
reed@google.com9998c662011-11-17 22:09:47 +000085bool SkEventSink::onEvent(const SkEvent&) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000086 return false;
87}
88
reed@google.com9998c662011-11-17 22:09:47 +000089bool SkEventSink::onQuery(SkEvent*) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 return false;
91}
92
93///////////////////////////////////////////////////////////////////////////////
94
reed@google.com9998c662011-11-17 22:09:47 +000095SkTagList* SkEventSink::findTagList(U8CPU tag) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000096 return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL;
97}
98
reed@google.com9998c662011-11-17 22:09:47 +000099void SkEventSink::addTagList(SkTagList* rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100 SkASSERT(rec);
101 SkASSERT(fTagHead == NULL || SkTagList::Find(fTagHead, rec->fTag) == NULL);
102
103 rec->fNext = fTagHead;
104 fTagHead = rec;
105}
106
reed@google.com9998c662011-11-17 22:09:47 +0000107void SkEventSink::removeTagList(U8CPU tag) {
108 if (fTagHead) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 SkTagList::DeleteTag(&fTagHead, tag);
reed@google.com9998c662011-11-17 22:09:47 +0000110 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111}
112
113///////////////////////////////////////////////////////////////////////////////
114
115struct SkListenersTagList : SkTagList {
116 SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
117 {
118 fExtra16 = SkToU16(count);
119 fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
120 }
121 virtual ~SkListenersTagList()
122 {
123 sk_free(fIDs);
124 }
125
126 int countListners() const { return fExtra16; }
127
128 int find(SkEventSinkID id) const
129 {
130 const SkEventSinkID* idptr = fIDs;
131 for (int i = fExtra16 - 1; i >= 0; --i)
132 if (idptr[i] == id)
133 return i;
134 return -1;
135 }
136
137 SkEventSinkID* fIDs;
138};
139
140void SkEventSink::addListenerID(SkEventSinkID id)
141{
142 if (id == 0)
143 return;
144
145 SkListenersTagList* prev = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
146 int count = 0;
147
148 if (prev)
149 {
150 if (prev->find(id) >= 0)
151 return;
152 count = prev->countListners();
153 }
154
155 SkListenersTagList* next = SkNEW_ARGS(SkListenersTagList, (count + 1));
156
157 if (prev)
158 {
159 memcpy(next->fIDs, prev->fIDs, count * sizeof(SkEventSinkID));
160 this->removeTagList(kListeners_SkTagList);
161 }
162 next->fIDs[count] = id;
163 this->addTagList(next);
164}
165
166void SkEventSink::copyListeners(const SkEventSink& sink)
167{
168 SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList);
169 if (sinkList == NULL)
170 return;
171 SkASSERT(sinkList->countListners() > 0);
172 const SkEventSinkID* iter = sinkList->fIDs;
173 const SkEventSinkID* stop = iter + sinkList->countListners();
174 while (iter < stop)
175 addListenerID(*iter++);
176}
177
178void SkEventSink::removeListenerID(SkEventSinkID id)
179{
180 if (id == 0)
181 return;
182
183 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
184
185 if (list == NULL)
186 return;
187
188 int index = list->find(id);
189 if (index >= 0)
190 {
191 int count = list->countListners();
192 SkASSERT(count > 0);
193 if (count == 1)
194 this->removeTagList(kListeners_SkTagList);
195 else
196 {
197 // overwrite without resize/reallocating our struct (for speed)
198 list->fIDs[index] = list->fIDs[count - 1];
199 list->fExtra16 = SkToU16(count - 1);
200 }
201 }
202}
203
204bool SkEventSink::hasListeners() const
205{
206 return this->findTagList(kListeners_SkTagList) != NULL;
207}
208
reed@google.com87fac4a2011-08-04 13:50:17 +0000209void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
reed@google.com87fac4a2011-08-04 13:50:17 +0000211 if (list) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 SkASSERT(list->countListners() > 0);
213 const SkEventSinkID* iter = list->fIDs;
214 const SkEventSinkID* stop = iter + list->countListners();
reed@google.com87fac4a2011-08-04 13:50:17 +0000215 while (iter < stop) {
216 SkEvent* copy = SkNEW_ARGS(SkEvent, (evt));
217 copy->setTargetID(*iter++)->postDelay(delay);
218 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 }
220}
221
222///////////////////////////////////////////////////////////////////////////////
223
reed@google.com87fac4a2011-08-04 13:50:17 +0000224SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt) {
225 SkEvent::Proc proc = evt.getTargetProc();
226 if (proc) {
227 return proc(evt) ? kHandled_EventResult : kNotHandled_EventResult;
228 }
229
230 SkEventSink* sink = SkEventSink::FindSink(evt.getTargetID());
231 if (sink) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
233 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234
reed@google.com87fac4a2011-08-04 13:50:17 +0000235 return kSinkNotFound_EventResult;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236}
237
238SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
239{
240 if (sinkID == 0)
241 return 0;
242
reed@google.com9998c662011-11-17 22:09:47 +0000243 SkEventSink_Globals& globals = getGlobals();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 SkAutoMutexAcquire ac(globals.fSinkMutex);
245 SkEventSink* sink = globals.fSinkHead;
246
247 while (sink)
248 {
249 if (sink->getSinkID() == sinkID)
250 return sink;
251 sink = sink->fNextSink;
252 }
253 return NULL;
254}
255
256////////////////////////////////////////////////////////////////////////////////////////
257////////////////////////////////////////////////////////////////////////////////////////
258
259#if 0 // experimental, not tested
260
261#include "SkThread.h"
262#include "SkTDict.h"
263
264#define kMinStringBufferSize 128
digit@google.com1771cbf2012-01-26 21:26:40 +0000265SK_DECLARE_STATIC_MUTEX(gNamedSinkMutex);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266static SkTDict<SkEventSinkID> gNamedSinkIDs(kMinStringBufferSize);
267
268/** Register a name/id pair with the system. If the name already exists,
269 replace its ID with the new id. This pair will persist until UnregisterNamedSink()
270 is called.
271*/
272void SkEventSink::RegisterNamedSinkID(const char name[], SkEventSinkID id)
273{
274 if (id && name && *name)
275 {
276 SkAutoMutexAcquire ac(gNamedSinkMutex);
277 gNamedSinkIDs.set(name, id);
278 }
279}
280
281/** Return the id that matches the specified name (from a previous call to
282 RegisterNamedSinkID(). If no match is found, return 0
283*/
284SkEventSinkID SkEventSink::FindNamedSinkID(const char name[])
285{
286 SkEventSinkID id = 0;
287
288 if (name && *name)
289 {
290 SkAutoMutexAcquire ac(gNamedSinkMutex);
291 (void)gNamedSinkIDs.find(name, &id);
292 }
293 return id;
294}
295
296/** Remove all name/id pairs from the system. This is call internally
297 on shutdown, to ensure no memory leaks. It should not be called
298 before shutdown.
299*/
300void SkEventSink::RemoveAllNamedSinkIDs()
301{
302 SkAutoMutexAcquire ac(gNamedSinkMutex);
303 (void)gNamedSinkIDs.reset();
304}
305#endif