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