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
17class SkEventSink_Globals {
18public:
19    SkEventSink_Globals() {
20        fNextSinkID = 0;
21        fSinkHead = NULL;
22    }
23
24    SkMutex         fSinkMutex;
25    SkEventSinkID   fNextSinkID;
26    SkEventSink*    fSinkHead;
27};
28
29static 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
35SkEventSink::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
47SkEventSink::~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
74bool SkEventSink::doEvent(const SkEvent& evt) {
75    return this->onEvent(evt);
76}
77
78bool SkEventSink::doQuery(SkEvent* evt) {
79    SkASSERT(evt);
80    return this->onQuery(evt);
81}
82
83bool SkEventSink::onEvent(const SkEvent&) {
84    return false;
85}
86
87bool SkEventSink::onQuery(SkEvent*) {
88    return false;
89}
90
91///////////////////////////////////////////////////////////////////////////////
92
93SkTagList* SkEventSink::findTagList(U8CPU tag) const {
94    return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL;
95}
96
97void 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
105void SkEventSink::removeTagList(U8CPU tag) {
106    if (fTagHead) {
107        SkTagList::DeleteTag(&fTagHead, tag);
108    }
109}
110
111///////////////////////////////////////////////////////////////////////////////
112
113struct SkListenersTagList : SkTagList {
114    SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
115    {
116        fExtra16 = SkToU16(count);
117        fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
118    }
119    virtual ~SkListenersTagList()
120    {
121        sk_free(fIDs);
122    }
123
124    int countListners() const { return fExtra16; }
125
126    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
138void 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
164void 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
176void 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
202bool SkEventSink::hasListeners() const
203{
204    return this->findTagList(kListeners_SkTagList) != NULL;
205}
206
207void 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
222SkEventSink::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
236SkEventSink* 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
263SK_DECLARE_STATIC_MUTEX(gNamedSinkMutex);
264static 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*/
270void 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*/
282SkEventSinkID 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*/
298void SkEventSink::RemoveAllNamedSinkIDs()
299{
300    SkAutoMutexAcquire  ac(gNamedSinkMutex);
301    (void)gNamedSinkIDs.reset();
302}
303#endif
304