• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libs/graphics/views/SkEventSink.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #include "SkEventSink.h"
19 #include "SkTagList.h"
20 #include "SkThread.h"
21 
22 #include "SkGlobals.h"
23 #include "SkThread.h"
24 #include "SkTime.h"
25 
26 #define SK_EventSink_GlobalsTag     SkSetFourByteTag('e', 'v', 's', 'k')
27 
28 class SkEventSink_Globals : public SkGlobals::Rec {
29 public:
30     SkMutex         fSinkMutex;
31     SkEventSinkID   fNextSinkID;
32     SkEventSink*    fSinkHead;
33 };
34 
create_globals()35 static SkGlobals::Rec* create_globals()
36 {
37     SkEventSink_Globals* rec = new SkEventSink_Globals;
38     rec->fNextSinkID = 0;
39     rec->fSinkHead = NULL;
40     return rec;
41 }
42 
SkEventSink()43 SkEventSink::SkEventSink() : fTagHead(NULL)
44 {
45     SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
46 
47     globals.fSinkMutex.acquire();
48 
49     fID = ++globals.fNextSinkID;
50     fNextSink = globals.fSinkHead;
51     globals.fSinkHead = this;
52 
53     globals.fSinkMutex.release();
54 }
55 
~SkEventSink()56 SkEventSink::~SkEventSink()
57 {
58     SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
59 
60     if (fTagHead)
61         SkTagList::DeleteAll(fTagHead);
62 
63     globals.fSinkMutex.acquire();
64 
65     SkEventSink* sink = globals.fSinkHead;
66     SkEventSink* prev = NULL;
67 
68     for (;;)
69     {
70         SkEventSink* next = sink->fNextSink;
71         if (sink == this)
72         {
73             if (prev)
74                 prev->fNextSink = next;
75             else
76                 globals.fSinkHead = next;
77             break;
78         }
79         prev = sink;
80         sink = next;
81     }
82     globals.fSinkMutex.release();
83 }
84 
doEvent(const SkEvent & evt)85 bool SkEventSink::doEvent(const SkEvent& evt)
86 {
87     return this->onEvent(evt);
88 }
89 
doQuery(SkEvent * evt)90 bool SkEventSink::doQuery(SkEvent* evt)
91 {
92     SkASSERT(evt);
93     return this->onQuery(evt);
94 }
95 
onEvent(const SkEvent &)96 bool SkEventSink::onEvent(const SkEvent&)
97 {
98     return false;
99 }
100 
onQuery(SkEvent *)101 bool SkEventSink::onQuery(SkEvent*)
102 {
103     return false;
104 }
105 
106 ///////////////////////////////////////////////////////////////////////////////
107 
findTagList(U8CPU tag) const108 SkTagList* SkEventSink::findTagList(U8CPU tag) const
109 {
110     return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL;
111 }
112 
addTagList(SkTagList * rec)113 void SkEventSink::addTagList(SkTagList* rec)
114 {
115     SkASSERT(rec);
116     SkASSERT(fTagHead == NULL || SkTagList::Find(fTagHead, rec->fTag) == NULL);
117 
118     rec->fNext = fTagHead;
119     fTagHead = rec;
120 }
121 
removeTagList(U8CPU tag)122 void SkEventSink::removeTagList(U8CPU tag)
123 {
124     if (fTagHead)
125         SkTagList::DeleteTag(&fTagHead, tag);
126 }
127 
128 ///////////////////////////////////////////////////////////////////////////////
129 
130 struct SkListenersTagList : SkTagList {
SkListenersTagListSkListenersTagList131     SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
132     {
133         fExtra16 = SkToU16(count);
134         fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
135     }
~SkListenersTagListSkListenersTagList136     virtual ~SkListenersTagList()
137     {
138         sk_free(fIDs);
139     }
140 
countListnersSkListenersTagList141     int countListners() const { return fExtra16; }
142 
findSkListenersTagList143     int find(SkEventSinkID id) const
144     {
145         const SkEventSinkID* idptr = fIDs;
146         for (int i = fExtra16 - 1; i >= 0; --i)
147             if (idptr[i] == id)
148                 return i;
149         return -1;
150     }
151 
152     SkEventSinkID*  fIDs;
153 };
154 
addListenerID(SkEventSinkID id)155 void SkEventSink::addListenerID(SkEventSinkID id)
156 {
157     if (id == 0)
158         return;
159 
160     SkListenersTagList* prev = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
161     int                 count = 0;
162 
163     if (prev)
164     {
165         if (prev->find(id) >= 0)
166             return;
167         count = prev->countListners();
168     }
169 
170     SkListenersTagList* next = SkNEW_ARGS(SkListenersTagList, (count + 1));
171 
172     if (prev)
173     {
174         memcpy(next->fIDs, prev->fIDs, count * sizeof(SkEventSinkID));
175         this->removeTagList(kListeners_SkTagList);
176     }
177     next->fIDs[count] = id;
178     this->addTagList(next);
179 }
180 
copyListeners(const SkEventSink & sink)181 void SkEventSink::copyListeners(const SkEventSink& sink)
182 {
183     SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList);
184     if (sinkList == NULL)
185         return;
186     SkASSERT(sinkList->countListners() > 0);
187     const SkEventSinkID* iter = sinkList->fIDs;
188     const SkEventSinkID* stop = iter + sinkList->countListners();
189     while (iter < stop)
190         addListenerID(*iter++);
191 }
192 
removeListenerID(SkEventSinkID id)193 void SkEventSink::removeListenerID(SkEventSinkID id)
194 {
195     if (id == 0)
196         return;
197 
198     SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
199 
200     if (list == NULL)
201         return;
202 
203     int index = list->find(id);
204     if (index >= 0)
205     {
206         int count = list->countListners();
207         SkASSERT(count > 0);
208         if (count == 1)
209             this->removeTagList(kListeners_SkTagList);
210         else
211         {
212             // overwrite without resize/reallocating our struct (for speed)
213             list->fIDs[index] = list->fIDs[count - 1];
214             list->fExtra16 = SkToU16(count - 1);
215         }
216     }
217 }
218 
hasListeners() const219 bool SkEventSink::hasListeners() const
220 {
221     return this->findTagList(kListeners_SkTagList) != NULL;
222 }
223 
postToListeners(const SkEvent & evt,SkMSec delay)224 void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay)
225 {
226     SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
227     if (list)
228     {
229         SkASSERT(list->countListners() > 0);
230         const SkEventSinkID* iter = list->fIDs;
231         const SkEventSinkID* stop = iter + list->countListners();
232         while (iter < stop)
233             (SkNEW_ARGS(SkEvent, (evt)))->post(*iter++, delay);
234     }
235 }
236 
237 ///////////////////////////////////////////////////////////////////////////////
238 
DoEvent(const SkEvent & evt,SkEventSinkID sinkID)239 SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt, SkEventSinkID sinkID)
240 {
241     SkEventSink* sink = SkEventSink::FindSink(sinkID);
242 
243     if (sink)
244     {
245 #ifdef SK_DEBUG
246         if (evt.isDebugTrace())
247         {
248             SkString    etype;
249             evt.getType(&etype);
250             SkDebugf("SkEventTrace: dispatching event <%s> to 0x%x", etype.c_str(), sinkID);
251             const char* idStr = evt.findString("id");
252             if (idStr)
253                 SkDebugf(" (%s)", idStr);
254             SkDebugf("\n");
255         }
256 #endif
257         return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
258     }
259     else
260     {
261 #ifdef SK_DEBUG
262         if (sinkID)
263             SkDebugf("DoEvent: Can't find sink for ID(%x)\n", sinkID);
264         else
265             SkDebugf("Event sent to 0 sinkID\n");
266 
267         if (evt.isDebugTrace())
268         {
269             SkString    etype;
270             evt.getType(&etype);
271             SkDebugf("SkEventTrace: eventsink not found <%s> for 0x%x\n", etype.c_str(), sinkID);
272         }
273 #endif
274         return kSinkNotFound_EventResult;
275     }
276 }
277 
FindSink(SkEventSinkID sinkID)278 SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
279 {
280     if (sinkID == 0)
281         return 0;
282 
283     SkEventSink_Globals&    globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
284     SkAutoMutexAcquire      ac(globals.fSinkMutex);
285     SkEventSink*            sink = globals.fSinkHead;
286 
287     while (sink)
288     {
289         if (sink->getSinkID() == sinkID)
290             return sink;
291         sink = sink->fNextSink;
292     }
293     return NULL;
294 }
295 
296 ////////////////////////////////////////////////////////////////////////////////////////
297 ////////////////////////////////////////////////////////////////////////////////////////
298 
299 #if 0   // experimental, not tested
300 
301 #include "SkThread.h"
302 #include "SkTDict.h"
303 
304 #define kMinStringBufferSize    128
305 static SkMutex                  gNamedSinkMutex;
306 static SkTDict<SkEventSinkID>   gNamedSinkIDs(kMinStringBufferSize);
307 
308 /** Register a name/id pair with the system. If the name already exists,
309     replace its ID with the new id. This pair will persist until UnregisterNamedSink()
310     is called.
311 */
312 void SkEventSink::RegisterNamedSinkID(const char name[], SkEventSinkID id)
313 {
314     if (id && name && *name)
315     {
316         SkAutoMutexAcquire  ac(gNamedSinkMutex);
317         gNamedSinkIDs.set(name, id);
318     }
319 }
320 
321 /** Return the id that matches the specified name (from a previous call to
322     RegisterNamedSinkID(). If no match is found, return 0
323 */
324 SkEventSinkID SkEventSink::FindNamedSinkID(const char name[])
325 {
326     SkEventSinkID id = 0;
327 
328     if (name && *name)
329     {
330         SkAutoMutexAcquire  ac(gNamedSinkMutex);
331         (void)gNamedSinkIDs.find(name, &id);
332     }
333     return id;
334 }
335 
336 /** Remove all name/id pairs from the system. This is call internally
337     on shutdown, to ensure no memory leaks. It should not be called
338     before shutdown.
339 */
340 void SkEventSink::RemoveAllNamedSinkIDs()
341 {
342     SkAutoMutexAcquire  ac(gNamedSinkMutex);
343     (void)gNamedSinkIDs.reset();
344 }
345 #endif
346