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