aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/views/SkEvent.cpp
diff options
context:
space:
mode:
authorGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2008-12-17 15:59:43 +0000
committerGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2008-12-17 15:59:43 +0000
commit8a1c16ff38322f0210116fa7293eb8817c7e477e (patch)
treefe40e07f6c8983318a2f79032b9a706ede1090c1 /src/views/SkEvent.cpp
parent2559c629078f738ac37095d896d580b681ac6a30 (diff)
grab from latest android
git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/views/SkEvent.cpp')
-rw-r--r--src/views/SkEvent.cpp565
1 files changed, 565 insertions, 0 deletions
diff --git a/src/views/SkEvent.cpp b/src/views/SkEvent.cpp
new file mode 100644
index 0000000000..67549b48b5
--- /dev/null
+++ b/src/views/SkEvent.cpp
@@ -0,0 +1,565 @@
+/* libs/graphics/views/SkEvent.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 "SkEvent.h"
+
+void SkEvent::initialize(const char* type, size_t typeLen) {
+ fType = NULL;
+ setType(type, typeLen);
+ f32 = 0;
+#ifdef SK_DEBUG
+ fTargetID = 0;
+ fTime = 0;
+ fNextEvent = NULL;
+#endif
+ SkDEBUGCODE(fDebugTrace = false;)
+}
+
+SkEvent::SkEvent()
+{
+ initialize("", 0);
+}
+
+SkEvent::SkEvent(const SkEvent& src)
+{
+ *this = src;
+ if (((size_t) fType & 1) == 0)
+ setType(src.fType);
+}
+
+SkEvent::SkEvent(const SkString& type)
+{
+ initialize(type.c_str(), type.size());
+}
+
+SkEvent::SkEvent(const char type[])
+{
+ SkASSERT(type);
+ initialize(type, strlen(type));
+}
+
+SkEvent::~SkEvent()
+{
+ if (((size_t) fType & 1) == 0)
+ sk_free((void*) fType);
+}
+
+static size_t makeCharArray(char* buffer, size_t compact)
+{
+ size_t bits = (size_t) compact >> 1;
+ memcpy(buffer, &bits, sizeof(compact));
+ buffer[sizeof(compact)] = 0;
+ return strlen(buffer);
+}
+
+#if 0
+const char* SkEvent::getType() const
+{
+ if ((size_t) fType & 1) { // not a pointer
+ char chars[sizeof(size_t) + 1];
+ size_t len = makeCharArray(chars, (size_t) fType);
+ fType = (char*) sk_malloc_throw(len);
+ SkASSERT(((size_t) fType & 1) == 0);
+ memcpy(fType, chars, len);
+ }
+ return fType;
+}
+#endif
+
+void SkEvent::getType(SkString* str) const
+{
+ if (str)
+ {
+ if ((size_t) fType & 1) // not a pointer
+ {
+ char chars[sizeof(size_t) + 1];
+ size_t len = makeCharArray(chars, (size_t) fType);
+ str->set(chars, len);
+ }
+ else
+ str->set(fType);
+ }
+}
+
+bool SkEvent::isType(const SkString& str) const
+{
+ return this->isType(str.c_str(), str.size());
+}
+
+bool SkEvent::isType(const char type[], size_t typeLen) const
+{
+ if (typeLen == 0)
+ typeLen = strlen(type);
+ if ((size_t) fType & 1) { // not a pointer
+ char chars[sizeof(size_t) + 1];
+ size_t len = makeCharArray(chars, (size_t) fType);
+ return len == typeLen && strncmp(chars, type, typeLen) == 0;
+ }
+ return strncmp(fType, type, typeLen) == 0 && fType[typeLen] == 0;
+}
+
+void SkEvent::setType(const char type[], size_t typeLen)
+{
+ if (typeLen == 0)
+ typeLen = strlen(type);
+ if (typeLen <= sizeof(fType)) {
+ size_t slot = 0;
+ memcpy(&slot, type, typeLen);
+ if (slot << 1 >> 1 != slot)
+ goto useCharStar;
+ slot <<= 1;
+ slot |= 1;
+ fType = (char*) slot;
+ } else {
+useCharStar:
+ fType = (char*) sk_malloc_throw(typeLen + 1);
+ SkASSERT(((size_t) fType & 1) == 0);
+ memcpy(fType, type, typeLen);
+ fType[typeLen] = 0;
+ }
+}
+
+void SkEvent::setType(const SkString& type)
+{
+ setType(type.c_str());
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+#include "SkParse.h"
+
+void SkEvent::inflate(const SkDOM& dom, const SkDOM::Node* node)
+{
+ const char* name = dom.findAttr(node, "type");
+ if (name)
+ this->setType(name);
+
+ const char* value;
+ if ((value = dom.findAttr(node, "fast32")) != NULL)
+ {
+ int32_t n;
+ if (SkParse::FindS32(value, &n))
+ this->setFast32(n);
+ }
+
+ for (node = dom.getFirstChild(node); node; node = dom.getNextSibling(node))
+ {
+ if (strcmp(dom.getName(node), "data"))
+ {
+ SkDEBUGCODE(SkDebugf("SkEvent::inflate unrecognized subelement <%s>\n", dom.getName(node));)
+ continue;
+ }
+
+ name = dom.findAttr(node, "name");
+ if (name == NULL)
+ {
+ SkDEBUGCODE(SkDebugf("SkEvent::inflate missing required \"name\" attribute in <data> subelement\n");)
+ continue;
+ }
+
+ if ((value = dom.findAttr(node, "s32")) != NULL)
+ {
+ int32_t n;
+ if (SkParse::FindS32(value, &n))
+ this->setS32(name, n);
+ }
+ else if ((value = dom.findAttr(node, "scalar")) != NULL)
+ {
+ SkScalar x;
+ if (SkParse::FindScalar(value, &x))
+ this->setScalar(name, x);
+ }
+ else if ((value = dom.findAttr(node, "string")) != NULL)
+ this->setString(name, value);
+#ifdef SK_DEBUG
+ else
+ {
+ SkDebugf("SkEvent::inflate <data name=\"%s\"> subelement missing required type attribute [S32 | scalar | string]\n", name);
+ }
+#endif
+ }
+}
+
+#ifdef SK_DEBUG
+
+ #ifndef SkScalarToFloat
+ #define SkScalarToFloat(x) ((x) / 65536.f)
+ #endif
+
+ void SkEvent::dump(const char title[])
+ {
+ if (title)
+ SkDebugf("%s ", title);
+
+ SkString etype;
+ this->getType(&etype);
+ SkDebugf("event<%s> fast32=%d", etype.c_str(), this->getFast32());
+
+ const SkMetaData& md = this->getMetaData();
+ SkMetaData::Iter iter(md);
+ SkMetaData::Type mtype;
+ int count;
+ const char* name;
+
+ while ((name = iter.next(&mtype, &count)) != NULL)
+ {
+ SkASSERT(count > 0);
+
+ SkDebugf(" <%s>=", name);
+ switch (mtype) {
+ case SkMetaData::kS32_Type: // vector version???
+ {
+ int32_t value;
+ md.findS32(name, &value);
+ SkDebugf("%d ", value);
+ }
+ break;
+ case SkMetaData::kScalar_Type:
+ {
+ const SkScalar* values = md.findScalars(name, &count, NULL);
+ SkDebugf("%f", SkScalarToFloat(values[0]));
+ for (int i = 1; i < count; i++)
+ SkDebugf(", %f", SkScalarToFloat(values[i]));
+ SkDebugf(" ");
+ }
+ break;
+ case SkMetaData::kString_Type:
+ {
+ const char* value = md.findString(name);
+ SkASSERT(value);
+ SkDebugf("<%s> ", value);
+ }
+ break;
+ case SkMetaData::kPtr_Type: // vector version???
+ {
+ void* value;
+ md.findPtr(name, &value);
+ SkDebugf("%p ", value);
+ }
+ break;
+ case SkMetaData::kBool_Type: // vector version???
+ {
+ bool value;
+ md.findBool(name, &value);
+ SkDebugf("%s ", value ? "true" : "false");
+ }
+ break;
+ default:
+ SkASSERT(!"unknown metadata type returned from iterator");
+ break;
+ }
+ }
+ SkDebugf("\n");
+ }
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+// #define SK_TRACE_EVENTSx
+#endif
+
+#ifdef SK_TRACE_EVENTS
+ static void event_log(const char s[])
+ {
+ SkDEBUGF(("%s\n", s));
+ }
+
+ #define EVENT_LOG(s) event_log(s)
+ #define EVENT_LOGN(s, n) do { SkString str(s); str.append(" "); str.appendS32(n); event_log(str.c_str()); } while (0)
+#else
+ #define EVENT_LOG(s)
+ #define EVENT_LOGN(s, n)
+#endif
+
+#include "SkGlobals.h"
+#include "SkThread.h"
+#include "SkTime.h"
+
+#define SK_Event_GlobalsTag SkSetFourByteTag('e', 'v', 'n', 't')
+
+class SkEvent_Globals : public SkGlobals::Rec {
+public:
+ SkMutex fEventMutex;
+ SkEvent* fEventQHead, *fEventQTail;
+ SkEvent* fDelayQHead;
+ SkDEBUGCODE(int fEventCounter;)
+};
+
+static SkGlobals::Rec* create_globals()
+{
+ SkEvent_Globals* rec = new SkEvent_Globals;
+ rec->fEventQHead = NULL;
+ rec->fEventQTail = NULL;
+ rec->fDelayQHead = NULL;
+ SkDEBUGCODE(rec->fEventCounter = 0;)
+ return rec;
+}
+
+bool SkEvent::Post(SkEvent* evt, SkEventSinkID sinkID, SkMSec delay)
+{
+ if (delay)
+ return SkEvent::PostTime(evt, sinkID, SkTime::GetMSecs() + delay);
+
+ SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+ evt->fTargetID = sinkID;
+
+#ifdef SK_TRACE_EVENTS
+ {
+ SkString str("SkEvent::Post(");
+ str.append(evt->getType());
+ str.append(", 0x");
+ str.appendHex(sinkID);
+ str.append(", ");
+ str.appendS32(delay);
+ str.append(")");
+ event_log(str.c_str());
+ }
+#endif
+
+ globals.fEventMutex.acquire();
+ bool wasEmpty = SkEvent::Enqueue(evt);
+ globals.fEventMutex.release();
+
+ // call outside of us holding the mutex
+ if (wasEmpty)
+ SkEvent::SignalNonEmptyQueue();
+ return true;
+}
+
+#if defined(SK_SIMULATE_FAILED_MALLOC) && defined(SK_FIND_MEMORY_LEAKS)
+SkMSec gMaxDrawTime;
+#endif
+
+bool SkEvent::PostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time)
+{
+#if defined(SK_SIMULATE_FAILED_MALLOC) && defined(SK_FIND_MEMORY_LEAKS)
+ gMaxDrawTime = time;
+#endif
+ SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+ evt->fTargetID = sinkID;
+
+#ifdef SK_TRACE_EVENTS
+ {
+ SkString str("SkEvent::Post(");
+ str.append(evt->getType());
+ str.append(", 0x");
+ str.appendHex(sinkID);
+ str.append(", ");
+ str.appendS32(time);
+ str.append(")");
+ event_log(str.c_str());
+ }
+#endif
+
+ globals.fEventMutex.acquire();
+ SkMSec queueDelay = SkEvent::EnqueueTime(evt, time);
+ globals.fEventMutex.release();
+
+ // call outside of us holding the mutex
+ if ((int32_t)queueDelay != ~0)
+ SkEvent::SignalQueueTimer(queueDelay);
+ return true;
+}
+
+bool SkEvent::Enqueue(SkEvent* evt)
+{
+ SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+ // gEventMutex acquired by caller
+
+ SkASSERT(evt);
+
+ bool wasEmpty = globals.fEventQHead == NULL;
+
+ if (globals.fEventQTail)
+ globals.fEventQTail->fNextEvent = evt;
+ globals.fEventQTail = evt;
+ if (globals.fEventQHead == NULL)
+ globals.fEventQHead = evt;
+ evt->fNextEvent = NULL;
+
+ SkDEBUGCODE(++globals.fEventCounter);
+// SkDebugf("Enqueue: count=%d\n", gEventCounter);
+
+ return wasEmpty;
+}
+
+SkEvent* SkEvent::Dequeue(SkEventSinkID* sinkID)
+{
+ SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+ globals.fEventMutex.acquire();
+
+ SkEvent* evt = globals.fEventQHead;
+ if (evt)
+ {
+ SkDEBUGCODE(--globals.fEventCounter);
+
+ if (sinkID)
+ *sinkID = evt->fTargetID;
+
+ globals.fEventQHead = evt->fNextEvent;
+ if (globals.fEventQHead == NULL)
+ globals.fEventQTail = NULL;
+ }
+ globals.fEventMutex.release();
+
+// SkDebugf("Dequeue: count=%d\n", gEventCounter);
+
+ return evt;
+}
+
+bool SkEvent::QHasEvents()
+{
+ SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+ // this is not thread accurate, need a semaphore for that
+ return globals.fEventQHead != NULL;
+}
+
+#ifdef SK_TRACE_EVENTS
+ static int gDelayDepth;
+#endif
+
+SkMSec SkEvent::EnqueueTime(SkEvent* evt, SkMSec time)
+{
+#ifdef SK_TRACE_EVENTS
+ SkDebugf("enqueue-delay %s %d (%d)", evt->getType(), time, gDelayDepth);
+ const char* idStr = evt->findString("id");
+ if (idStr)
+ SkDebugf(" (%s)", idStr);
+ SkDebugf("\n");
+ ++gDelayDepth;
+#endif
+
+ SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+ // gEventMutex acquired by caller
+
+ SkEvent* curr = globals.fDelayQHead;
+ SkEvent* prev = NULL;
+
+ while (curr)
+ {
+ if (SkMSec_LT(time, curr->fTime))
+ break;
+ prev = curr;
+ curr = curr->fNextEvent;
+ }
+
+ evt->fTime = time;
+ evt->fNextEvent = curr;
+ if (prev == NULL)
+ globals.fDelayQHead = evt;
+ else
+ prev->fNextEvent = evt;
+
+ SkMSec delay = globals.fDelayQHead->fTime - SkTime::GetMSecs();
+ if ((int32_t)delay <= 0)
+ delay = 1;
+ return delay;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#include "SkEventSink.h"
+
+bool SkEvent::ProcessEvent()
+{
+ SkEventSinkID sinkID;
+ SkEvent* evt = SkEvent::Dequeue(&sinkID);
+ SkAutoTDelete<SkEvent> autoDelete(evt);
+ bool again = false;
+
+ EVENT_LOGN("ProcessEvent", (int32_t)evt);
+
+ if (evt)
+ {
+ (void)SkEventSink::DoEvent(*evt, sinkID);
+ again = SkEvent::QHasEvents();
+ }
+ return again;
+}
+
+void SkEvent::ServiceQueueTimer()
+{
+ SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+ globals.fEventMutex.acquire();
+
+ bool wasEmpty = false;
+ SkMSec now = SkTime::GetMSecs();
+ SkEvent* evt = globals.fDelayQHead;
+
+ while (evt)
+ {
+ if (SkMSec_LT(now, evt->fTime))
+ break;
+
+#ifdef SK_TRACE_EVENTS
+ --gDelayDepth;
+ SkDebugf("dequeue-delay %s (%d)", evt->getType(), gDelayDepth);
+ const char* idStr = evt->findString("id");
+ if (idStr)
+ SkDebugf(" (%s)", idStr);
+ SkDebugf("\n");
+#endif
+
+ SkEvent* next = evt->fNextEvent;
+ if (SkEvent::Enqueue(evt))
+ wasEmpty = true;
+ evt = next;
+ }
+ globals.fDelayQHead = evt;
+
+ SkMSec time = evt ? evt->fTime - now : 0;
+
+ globals.fEventMutex.release();
+
+ if (wasEmpty)
+ SkEvent::SignalNonEmptyQueue();
+
+ SkEvent::SignalQueueTimer(time);
+}
+
+////////////////////////////////////////////////////////////////
+
+void SkEvent::Init()
+{
+}
+
+void SkEvent::Term()
+{
+ SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+ SkEvent* evt = globals.fEventQHead;
+ while (evt)
+ {
+ SkEvent* next = evt->fNextEvent;
+ delete evt;
+ evt = next;
+ }
+
+ evt = globals.fDelayQHead;
+ while (evt)
+ {
+ SkEvent* next = evt->fNextEvent;
+ delete evt;
+ evt = next;
+ }
+}
+