blob: cd83111f50723ab147217ddc8c9265e264670f0f [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00008
9#include "SkEventSink.h"
mtklein1b249332015-07-07 12:21:21 -070010#include "SkMutex.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkTagList.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkTime.h"
13
reed@google.com9998c662011-11-17 22:09:47 +000014class SkEventSink_Globals {
reed@android.com8a1c16f2008-12-17 15:59:43 +000015public:
reed@google.com9998c662011-11-17 22:09:47 +000016 SkEventSink_Globals() {
17 fNextSinkID = 0;
halcanary96fcdcc2015-08-27 07:41:13 -070018 fSinkHead = nullptr;
reed@google.com9998c662011-11-17 22:09:47 +000019 }
20
reed@android.com8a1c16f2008-12-17 15:59:43 +000021 SkMutex fSinkMutex;
22 SkEventSinkID fNextSinkID;
23 SkEventSink* fSinkHead;
24};
25
reed@google.com9998c662011-11-17 22:09:47 +000026static 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;
reed@android.com8a1c16f2008-12-17 15:59:43 +000030}
31
halcanary96fcdcc2015-08-27 07:41:13 -070032SkEventSink::SkEventSink() : fTagHead(nullptr) {
reed@google.com9998c662011-11-17 22:09:47 +000033 SkEventSink_Globals& globals = getGlobals();
reed@android.com8a1c16f2008-12-17 15:59:43 +000034
35 globals.fSinkMutex.acquire();
36
37 fID = ++globals.fNextSinkID;
38 fNextSink = globals.fSinkHead;
39 globals.fSinkHead = this;
40
41 globals.fSinkMutex.release();
42}
43
reed@google.com9998c662011-11-17 22:09:47 +000044SkEventSink::~SkEventSink() {
45 SkEventSink_Globals& globals = getGlobals();
reed@android.com8a1c16f2008-12-17 15:59:43 +000046
47 if (fTagHead)
48 SkTagList::DeleteAll(fTagHead);
49
50 globals.fSinkMutex.acquire();
51
52 SkEventSink* sink = globals.fSinkHead;
halcanary96fcdcc2015-08-27 07:41:13 -070053 SkEventSink* prev = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +000054
reed@google.com9998c662011-11-17 22:09:47 +000055 for (;;) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 SkEventSink* next = sink->fNextSink;
reed@google.com9998c662011-11-17 22:09:47 +000057 if (sink == this) {
58 if (prev) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 prev->fNextSink = next;
reed@google.com9998c662011-11-17 22:09:47 +000060 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 globals.fSinkHead = next;
reed@google.com9998c662011-11-17 22:09:47 +000062 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 break;
64 }
65 prev = sink;
66 sink = next;
67 }
68 globals.fSinkMutex.release();
69}
70
reed@google.com9998c662011-11-17 22:09:47 +000071bool SkEventSink::doEvent(const SkEvent& evt) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000072 return this->onEvent(evt);
73}
74
reed@google.com9998c662011-11-17 22:09:47 +000075bool SkEventSink::doQuery(SkEvent* evt) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 SkASSERT(evt);
77 return this->onQuery(evt);
78}
79
reed@google.com9998c662011-11-17 22:09:47 +000080bool SkEventSink::onEvent(const SkEvent&) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 return false;
82}
83
reed@google.com9998c662011-11-17 22:09:47 +000084bool SkEventSink::onQuery(SkEvent*) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 return false;
86}
87
88///////////////////////////////////////////////////////////////////////////////
89
reed@google.com9998c662011-11-17 22:09:47 +000090SkTagList* SkEventSink::findTagList(U8CPU tag) const {
halcanary96fcdcc2015-08-27 07:41:13 -070091 return fTagHead ? SkTagList::Find(fTagHead, tag) : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +000092}
93
reed@google.com9998c662011-11-17 22:09:47 +000094void SkEventSink::addTagList(SkTagList* rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 SkASSERT(rec);
halcanary96fcdcc2015-08-27 07:41:13 -070096 SkASSERT(fTagHead == nullptr || SkTagList::Find(fTagHead, rec->fTag) == nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +000097
98 rec->fNext = fTagHead;
99 fTagHead = rec;
100}
101
reed@google.com9998c662011-11-17 22:09:47 +0000102void SkEventSink::removeTagList(U8CPU tag) {
103 if (fTagHead) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 SkTagList::DeleteTag(&fTagHead, tag);
reed@google.com9998c662011-11-17 22:09:47 +0000105 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106}
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
halcanary385fe4d2015-08-26 13:07:48 -0700150 SkListenersTagList* next = new SkListenersTagList(count + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151
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
rmistry@google.comd6176b02012-08-23 18:14:13 +0000161void SkEventSink::copyListeners(const SkEventSink& sink)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162{
163 SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList);
halcanary96fcdcc2015-08-27 07:41:13 -0700164 if (sinkList == nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 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
halcanary96fcdcc2015-08-27 07:41:13 -0700180 if (list == nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181 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{
halcanary96fcdcc2015-08-27 07:41:13 -0700201 return this->findTagList(kListeners_SkTagList) != nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202}
203
reed@google.com87fac4a2011-08-04 13:50:17 +0000204void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
reed@google.com87fac4a2011-08-04 13:50:17 +0000206 if (list) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 SkASSERT(list->countListners() > 0);
208 const SkEventSinkID* iter = list->fIDs;
209 const SkEventSinkID* stop = iter + list->countListners();
reed@google.com87fac4a2011-08-04 13:50:17 +0000210 while (iter < stop) {
halcanary385fe4d2015-08-26 13:07:48 -0700211 SkEvent* copy = new SkEvent(evt);
reed@google.com87fac4a2011-08-04 13:50:17 +0000212 copy->setTargetID(*iter++)->postDelay(delay);
213 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 }
215}
216
217///////////////////////////////////////////////////////////////////////////////
218
reed@google.com87fac4a2011-08-04 13:50:17 +0000219SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt) {
220 SkEvent::Proc proc = evt.getTargetProc();
221 if (proc) {
222 return proc(evt) ? kHandled_EventResult : kNotHandled_EventResult;
223 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000224
reed@google.com87fac4a2011-08-04 13:50:17 +0000225 SkEventSink* sink = SkEventSink::FindSink(evt.getTargetID());
226 if (sink) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
228 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229
reed@google.com87fac4a2011-08-04 13:50:17 +0000230 return kSinkNotFound_EventResult;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231}
232
233SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
234{
235 if (sinkID == 0)
Ben Wagnera93a14a2017-08-28 10:34:05 -0400236 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
reed@google.com9998c662011-11-17 22:09:47 +0000238 SkEventSink_Globals& globals = getGlobals();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 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 }
halcanary96fcdcc2015-08-27 07:41:13 -0700248 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249}