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
17SK_DEFINE_INST_COUNT(SkEventSink)
18
19class SkEventSink_Globals {
20public:
21    SkEventSink_Globals() {
22        fNextSinkID = 0;
23        fSinkHead = NULL;
24    }
25
26    SkMutex         fSinkMutex;
27    SkEventSinkID   fNextSinkID;
28    SkEventSink*    fSinkHead;
29};
30
31static 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;
35}
36
37SkEventSink::SkEventSink() : fTagHead(NULL) {
38    SkEventSink_Globals& globals = getGlobals();
39
40    globals.fSinkMutex.acquire();
41
42    fID = ++globals.fNextSinkID;
43    fNextSink = globals.fSinkHead;
44    globals.fSinkHead = this;
45
46    globals.fSinkMutex.release();
47}
48
49SkEventSink::~SkEventSink() {
50    SkEventSink_Globals& globals = getGlobals();
51
52    if (fTagHead)
53        SkTagList::DeleteAll(fTagHead);
54
55    globals.fSinkMutex.acquire();
56
57    SkEventSink* sink = globals.fSinkHead;
58    SkEventSink* prev = NULL;
59
60    for (;;) {
61        SkEventSink* next = sink->fNextSink;
62        if (sink == this) {
63            if (prev) {
64                prev->fNextSink = next;
65            } else {
66                globals.fSinkHead = next;
67            }
68            break;
69        }
70        prev = sink;
71        sink = next;
72    }
73    globals.fSinkMutex.release();
74}
75
76bool SkEventSink::doEvent(const SkEvent& evt) {
77    return this->onEvent(evt);
78}
79
80bool SkEventSink::doQuery(SkEvent* evt) {
81    SkASSERT(evt);
82    return this->onQuery(evt);
83}
84
85bool SkEventSink::onEvent(const SkEvent&) {
86    return false;
87}
88
89bool SkEventSink::onQuery(SkEvent*) {
90    return false;
91}
92
93///////////////////////////////////////////////////////////////////////////////
94
95SkTagList* SkEventSink::findTagList(U8CPU tag) const {
96    return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL;
97}
98
99void SkEventSink::addTagList(SkTagList* rec) {
100    SkASSERT(rec);
101    SkASSERT(fTagHead == NULL || SkTagList::Find(fTagHead, rec->fTag) == NULL);
102
103    rec->fNext = fTagHead;
104    fTagHead = rec;
105}
106
107void SkEventSink::removeTagList(U8CPU tag) {
108    if (fTagHead) {
109        SkTagList::DeleteTag(&fTagHead, tag);
110    }
111}
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
209void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay) {
210    SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
211    if (list) {
212        SkASSERT(list->countListners() > 0);
213        const SkEventSinkID* iter = list->fIDs;
214        const SkEventSinkID* stop = iter + list->countListners();
215        while (iter < stop) {
216            SkEvent* copy = SkNEW_ARGS(SkEvent, (evt));
217            copy->setTargetID(*iter++)->postDelay(delay);
218        }
219    }
220}
221
222///////////////////////////////////////////////////////////////////////////////
223
224SkEventSink::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) {
232        return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
233    }
234
235    return kSinkNotFound_EventResult;
236}
237
238SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
239{
240    if (sinkID == 0)
241        return 0;
242
243    SkEventSink_Globals&    globals = getGlobals();
244    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
265SK_DECLARE_STATIC_MUTEX(gNamedSinkMutex);
266static 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
306