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