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
15class SkEventSink_Globals {
16public:
17    SkEventSink_Globals() {
18        fNextSinkID = 0;
19        fSinkHead = nullptr;
20    }
21
22    SkMutex         fSinkMutex;
23    SkEventSinkID   fNextSinkID;
24    SkEventSink*    fSinkHead;
25};
26
27static 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
33SkEventSink::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
45SkEventSink::~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
72bool SkEventSink::doEvent(const SkEvent& evt) {
73    return this->onEvent(evt);
74}
75
76bool SkEventSink::doQuery(SkEvent* evt) {
77    SkASSERT(evt);
78    return this->onQuery(evt);
79}
80
81bool SkEventSink::onEvent(const SkEvent&) {
82    return false;
83}
84
85bool SkEventSink::onQuery(SkEvent*) {
86    return false;
87}
88
89///////////////////////////////////////////////////////////////////////////////
90
91SkTagList* SkEventSink::findTagList(U8CPU tag) const {
92    return fTagHead ? SkTagList::Find(fTagHead, tag) : nullptr;
93}
94
95void 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
103void SkEventSink::removeTagList(U8CPU tag) {
104    if (fTagHead) {
105        SkTagList::DeleteTag(&fTagHead, tag);
106    }
107}
108
109///////////////////////////////////////////////////////////////////////////////
110
111struct SkListenersTagList : SkTagList {
112    SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
113    {
114        fExtra16 = SkToU16(count);
115        fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
116    }
117    virtual ~SkListenersTagList()
118    {
119        sk_free(fIDs);
120    }
121
122    int countListners() const { return fExtra16; }
123
124    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
136void 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
162void 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
174void 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
200bool SkEventSink::hasListeners() const
201{
202    return this->findTagList(kListeners_SkTagList) != nullptr;
203}
204
205void 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
220SkEventSink::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
234SkEventSink* 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
261SK_DECLARE_STATIC_MUTEX(gNamedSinkMutex);
262static 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*/
268void 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*/
280SkEventSinkID 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*/
296void SkEventSink::RemoveAllNamedSinkIDs()
297{
298    SkAutoMutexAcquire  ac(gNamedSinkMutex);
299    (void)gNamedSinkIDs.reset();
300}
301#endif
302