grab from latest android



git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/views/SkEventSink.cpp b/src/views/SkEventSink.cpp
new file mode 100644
index 0000000..c8fe35c
--- /dev/null
+++ b/src/views/SkEventSink.cpp
@@ -0,0 +1,345 @@
+/* libs/graphics/views/SkEventSink.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include "SkEventSink.h"
+#include "SkTagList.h"
+#include "SkThread.h"
+
+#include "SkGlobals.h"
+#include "SkThread.h"
+#include "SkTime.h"
+
+#define SK_EventSink_GlobalsTag     SkSetFourByteTag('e', 'v', 's', 'k')
+
+class SkEventSink_Globals : public SkGlobals::Rec {
+public:
+    SkMutex         fSinkMutex;
+    SkEventSinkID   fNextSinkID;
+    SkEventSink*    fSinkHead;
+};
+
+static SkGlobals::Rec* create_globals()
+{
+    SkEventSink_Globals* rec = new SkEventSink_Globals;
+    rec->fNextSinkID = 0;
+    rec->fSinkHead = NULL;
+    return rec;
+}
+
+SkEventSink::SkEventSink() : fTagHead(NULL)
+{
+    SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
+
+    globals.fSinkMutex.acquire();
+
+    fID = ++globals.fNextSinkID;
+    fNextSink = globals.fSinkHead;
+    globals.fSinkHead = this;
+
+    globals.fSinkMutex.release();
+}
+
+SkEventSink::~SkEventSink()
+{
+    SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
+
+    if (fTagHead)
+        SkTagList::DeleteAll(fTagHead);
+
+    globals.fSinkMutex.acquire();
+
+    SkEventSink* sink = globals.fSinkHead;
+    SkEventSink* prev = NULL;
+
+    for (;;)
+    {
+        SkEventSink* next = sink->fNextSink;
+        if (sink == this)
+        {
+            if (prev)
+                prev->fNextSink = next;
+            else
+                globals.fSinkHead = next;
+            break;
+        }
+        prev = sink;
+        sink = next;
+    }
+    globals.fSinkMutex.release();
+}
+
+bool SkEventSink::doEvent(const SkEvent& evt)
+{
+    return this->onEvent(evt);
+}
+
+bool SkEventSink::doQuery(SkEvent* evt)
+{
+    SkASSERT(evt);
+    return this->onQuery(evt);
+}
+
+bool SkEventSink::onEvent(const SkEvent&)
+{
+    return false;
+}
+
+bool SkEventSink::onQuery(SkEvent*)
+{
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkTagList* SkEventSink::findTagList(U8CPU tag) const
+{
+    return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL;
+}
+
+void SkEventSink::addTagList(SkTagList* rec)
+{
+    SkASSERT(rec);
+    SkASSERT(fTagHead == NULL || SkTagList::Find(fTagHead, rec->fTag) == NULL);
+
+    rec->fNext = fTagHead;
+    fTagHead = rec;
+}
+
+void SkEventSink::removeTagList(U8CPU tag)
+{
+    if (fTagHead)
+        SkTagList::DeleteTag(&fTagHead, tag);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct SkListenersTagList : SkTagList {
+    SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
+    {
+        fExtra16 = SkToU16(count);
+        fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
+    }
+    virtual ~SkListenersTagList()
+    {
+        sk_free(fIDs);
+    }
+
+    int countListners() const { return fExtra16; }
+
+    int find(SkEventSinkID id) const
+    {
+        const SkEventSinkID* idptr = fIDs;
+        for (int i = fExtra16 - 1; i >= 0; --i)
+            if (idptr[i] == id)
+                return i;
+        return -1;
+    }
+
+    SkEventSinkID*  fIDs;
+};
+
+void SkEventSink::addListenerID(SkEventSinkID id)
+{
+    if (id == 0)
+        return;
+
+    SkListenersTagList* prev = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
+    int                 count = 0;
+
+    if (prev)
+    {
+        if (prev->find(id) >= 0)
+            return;
+        count = prev->countListners();
+    }
+
+    SkListenersTagList* next = SkNEW_ARGS(SkListenersTagList, (count + 1));
+
+    if (prev)
+    {
+        memcpy(next->fIDs, prev->fIDs, count * sizeof(SkEventSinkID));
+        this->removeTagList(kListeners_SkTagList);
+    }
+    next->fIDs[count] = id;
+    this->addTagList(next);
+}
+
+void SkEventSink::copyListeners(const SkEventSink& sink) 
+{
+    SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList);
+    if (sinkList == NULL)
+        return;
+    SkASSERT(sinkList->countListners() > 0);
+    const SkEventSinkID* iter = sinkList->fIDs;
+    const SkEventSinkID* stop = iter + sinkList->countListners();
+    while (iter < stop)
+        addListenerID(*iter++);
+}
+
+void SkEventSink::removeListenerID(SkEventSinkID id)
+{
+    if (id == 0)
+        return;
+
+    SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
+
+    if (list == NULL)
+        return;
+
+    int index = list->find(id);
+    if (index >= 0)
+    {
+        int count = list->countListners();
+        SkASSERT(count > 0);
+        if (count == 1)
+            this->removeTagList(kListeners_SkTagList);
+        else
+        {
+            // overwrite without resize/reallocating our struct (for speed)
+            list->fIDs[index] = list->fIDs[count - 1];
+            list->fExtra16 = SkToU16(count - 1);
+        }
+    }
+}
+
+bool SkEventSink::hasListeners() const
+{
+    return this->findTagList(kListeners_SkTagList) != NULL;
+}
+
+void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay)
+{
+    SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
+    if (list)
+    {
+        SkASSERT(list->countListners() > 0);
+        const SkEventSinkID* iter = list->fIDs;
+        const SkEventSinkID* stop = iter + list->countListners();
+        while (iter < stop)
+            (SkNEW_ARGS(SkEvent, (evt)))->post(*iter++, delay);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt, SkEventSinkID sinkID)
+{
+    SkEventSink* sink = SkEventSink::FindSink(sinkID);
+
+    if (sink)
+    {
+#ifdef SK_DEBUG
+        if (evt.isDebugTrace())
+        {
+            SkString    etype;
+            evt.getType(&etype);
+            SkDebugf("SkEventTrace: dispatching event <%s> to 0x%x", etype.c_str(), sinkID);
+            const char* idStr = evt.findString("id");
+            if (idStr)
+                SkDebugf(" (%s)", idStr);
+            SkDebugf("\n");
+        }
+#endif
+        return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
+    }
+    else
+    {
+#ifdef SK_DEBUG
+        if (sinkID)
+            SkDebugf("DoEvent: Can't find sink for ID(%x)\n", sinkID);
+        else
+            SkDebugf("Event sent to 0 sinkID\n");
+
+        if (evt.isDebugTrace())
+        {
+            SkString    etype;
+            evt.getType(&etype);
+            SkDebugf("SkEventTrace: eventsink not found <%s> for 0x%x\n", etype.c_str(), sinkID);
+        }
+#endif
+        return kSinkNotFound_EventResult;
+    }
+}
+
+SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
+{
+    if (sinkID == 0)
+        return 0;
+
+    SkEventSink_Globals&    globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
+    SkAutoMutexAcquire      ac(globals.fSinkMutex);
+    SkEventSink*            sink = globals.fSinkHead;
+
+    while (sink)
+    {
+        if (sink->getSinkID() == sinkID)
+            return sink;
+        sink = sink->fNextSink;
+    }
+    return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////
+
+#if 0   // experimental, not tested
+
+#include "SkThread.h"
+#include "SkTDict.h"
+
+#define kMinStringBufferSize    128
+static SkMutex                  gNamedSinkMutex;
+static SkTDict<SkEventSinkID>   gNamedSinkIDs(kMinStringBufferSize);
+
+/** Register a name/id pair with the system. If the name already exists,
+    replace its ID with the new id. This pair will persist until UnregisterNamedSink()
+    is called.
+*/
+void SkEventSink::RegisterNamedSinkID(const char name[], SkEventSinkID id)
+{
+    if (id && name && *name)
+    {
+        SkAutoMutexAcquire  ac(gNamedSinkMutex);
+        gNamedSinkIDs.set(name, id);
+    }
+}
+
+/** Return the id that matches the specified name (from a previous call to
+    RegisterNamedSinkID(). If no match is found, return 0
+*/
+SkEventSinkID SkEventSink::FindNamedSinkID(const char name[])
+{
+    SkEventSinkID id = 0;
+
+    if (name && *name)
+    {
+        SkAutoMutexAcquire  ac(gNamedSinkMutex);
+        (void)gNamedSinkIDs.find(name, &id);
+    }
+    return id;
+}
+
+/** Remove all name/id pairs from the system. This is call internally
+    on shutdown, to ensure no memory leaks. It should not be called
+    before shutdown.
+*/
+void SkEventSink::RemoveAllNamedSinkIDs()
+{
+    SkAutoMutexAcquire  ac(gNamedSinkMutex);
+    (void)gNamedSinkIDs.reset();
+}
+#endif