C++程序  |  566行  |  14.3 KB

/* 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;
    }
}