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