| /* 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); |
| } |
| |
| int SkEvent::CountEventsOnQueue() { |
| SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals); |
| globals.fEventMutex.acquire(); |
| |
| int count = 0; |
| const SkEvent* evt = globals.fEventQHead; |
| while (evt) { |
| count += 1; |
| evt = evt->fNextEvent; |
| } |
| globals.fEventMutex.release(); |
| |
| return count; |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| 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; |
| } |
| } |
| |