retool SkEvent to own its target ID or target proc

git-svn-id: http://skia.googlecode.com/svn/trunk@2041 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2011-08-04 13:50:17 +00:00
parent 5aa937b300
commit 87fac4abd7
13 changed files with 288 additions and 323 deletions

View File

@ -21,71 +21,111 @@
*/
typedef uint32_t SkEventSinkID;
/** \class SkEvent
SkEvents are used to communicate type-safe information to SkEventSinks.
SkEventSinks (including SkViews) each have a unique ID, which is stored
in an event. This ID is used to target the event once it has been "posted".
*/
/**
* \class SkEvent
*
* When an event is dispatched from the event queue, it is either sent to
* the eventsink matching the target ID (if not 0), or the target proc is
* called (if not NULL).
*/
class SkEvent {
public:
/** Default construct, creating an empty event.
*/
/**
* Function pointer that takes an event, returns true if it "handled" it.
*/
typedef bool (*Proc)(const SkEvent& evt);
SkEvent();
/** Construct a new event with the specified type.
*/
explicit SkEvent(const SkString& type);
/** Construct a new event with the specified type.
*/
explicit SkEvent(const char type[]);
/** Construct a new event by copying the fields from the src event.
*/
explicit SkEvent(const SkString& type, SkEventSinkID = 0);
explicit SkEvent(const char type[], SkEventSinkID = 0);
SkEvent(const SkEvent& src);
~SkEvent();
/** Copy the event's type into the specified SkString parameter */
void getType(SkString* str) const;
void getType(SkString* str) const;
/** Returns true if the event's type matches exactly the specified type (case sensitive) */
bool isType(const SkString& str) const;
bool isType(const SkString& str) const;
/** Returns true if the event's type matches exactly the specified type (case sensitive) */
bool isType(const char type[], size_t len = 0) const;
/** Set the event's type to the specified string.
In XML, use the "type" attribute.
*/
void setType(const SkString&);
/** Set the event's type to the specified string.
In XML, use the "type" attribute.
*/
void setType(const char type[], size_t len = 0);
bool isType(const char type[], size_t len = 0) const;
/**
* Set the event's type to the specified string.
*/
void setType(const SkString&);
/**
* Set the event's type to the specified string.
*/
void setType(const char type[], size_t len = 0);
/**
* Return the target ID, or 0 if there is none.
*
* When an event is dispatched from the event queue, it is either sent to
* the eventsink matching the targetID (if not 0), or the target proc is
* called (if not NULL).
*/
SkEventSinkID getTargetID() const { return fTargetID; }
/**
* Set the target ID for this event. 0 means none. Can be specified when
* the event is posted or sent.
* Set the target ID for this event. 0 means none. Calling this will
* automatically clear the targetProc to null.
*
* When an event is dispatched from the event queue, it is either sent to
* the eventsink matching the targetID (if not 0), or the target proc is
* called (if not NULL).
*/
void setTargetID(SkEventSinkID targetID) { fTargetID = targetID; }
SkEvent* setTargetID(SkEventSinkID targetID) {
fTargetProc = NULL;
fTargetID = targetID;
return this;
}
/** Return the event's unnamed 32bit field. Default value is 0 */
/**
* Return the target proc, or NULL if it has none.
*
* When an event is dispatched from the event queue, it is either sent to
* the eventsink matching the targetID (if not 0), or the target proc is
* called (if not NULL).
*/
Proc getTargetProc() const { return fTargetProc; }
/**
* Set the target ID for this event. NULL means none. Calling this will
* automatically clear the targetID to 0.
*
* When an event is dispatched from the event queue, it is either sent to
* the eventsink matching the targetID (if not 0), or the target proc is
* called (if not NULL).
*/
SkEvent* setTargetProc(Proc proc) {
fTargetID = 0;
fTargetProc = proc;
return this;
}
/**
* Return the event's unnamed 32bit field. Default value is 0
*/
uint32_t getFast32() const { return f32; }
/** Set the event's unnamed 32bit field. In XML, use
the subelement <data fast32=... />
*/
void setFast32(uint32_t x) { f32 = x; }
/**
* Set the event's unnamed 32bit field.
*/
void setFast32(uint32_t x) { f32 = x; }
/** Return true if the event contains the named 32bit field, and return the field
in value (if value is non-null). If there is no matching named field, return false
and ignore the value parameter.
*/
bool findS32(const char name[], int32_t* value = NULL) const { return fMeta.findS32(name, value); }
bool findS32(const char name[], int32_t* value = NULL) const { return fMeta.findS32(name, value); }
/** Return true if the event contains the named SkScalar field, and return the field
in value (if value is non-null). If there is no matching named field, return false
and ignore the value parameter.
*/
bool findScalar(const char name[], SkScalar* value = NULL) const { return fMeta.findScalar(name, value); }
bool findScalar(const char name[], SkScalar* value = NULL) const { return fMeta.findScalar(name, value); }
/** Return true if the event contains the named SkScalar field, and return the fields
in value[] (if value is non-null), and return the number of SkScalars in count (if count is non-null).
If there is no matching named field, return false and ignore the value and count parameters.
@ -98,112 +138,82 @@ public:
in value (if value is non-null). If there is no matching named field, return false
and ignore the value parameter.
*/
bool findPtr(const char name[], void** value) const { return fMeta.findPtr(name, value); }
bool findBool(const char name[], bool* value) const { return fMeta.findBool(name, value); }
bool findPtr(const char name[], void** value) const { return fMeta.findPtr(name, value); }
bool findBool(const char name[], bool* value) const { return fMeta.findBool(name, value); }
const void* findData(const char name[], size_t* byteCount = NULL) const {
return fMeta.findData(name, byteCount);
}
/** Returns true if ethe event contains the named 32bit field, and if it equals the specified value */
bool hasS32(const char name[], int32_t value) const { return fMeta.hasS32(name, value); }
bool hasS32(const char name[], int32_t value) const { return fMeta.hasS32(name, value); }
/** Returns true if ethe event contains the named SkScalar field, and if it equals the specified value */
bool hasScalar(const char name[], SkScalar value) const { return fMeta.hasScalar(name, value); }
bool hasScalar(const char name[], SkScalar value) const { return fMeta.hasScalar(name, value); }
/** Returns true if ethe event contains the named string field, and if it equals (using strcmp) the specified value */
bool hasString(const char name[], const char value[]) const { return fMeta.hasString(name, value); }
bool hasString(const char name[], const char value[]) const { return fMeta.hasString(name, value); }
/** Returns true if ethe event contains the named pointer field, and if it equals the specified value */
bool hasPtr(const char name[], void* value) const { return fMeta.hasPtr(name, value); }
bool hasBool(const char name[], bool value) const { return fMeta.hasBool(name, value); }
bool hasPtr(const char name[], void* value) const { return fMeta.hasPtr(name, value); }
bool hasBool(const char name[], bool value) const { return fMeta.hasBool(name, value); }
bool hasData(const char name[], const void* data, size_t byteCount) const {
return fMeta.hasData(name, data, byteCount);
}
/** Add/replace the named 32bit field to the event. In XML use the subelement <data name=... s32=... /> */
void setS32(const char name[], int32_t value) { fMeta.setS32(name, value); }
void setS32(const char name[], int32_t value) { fMeta.setS32(name, value); }
/** Add/replace the named SkScalar field to the event. In XML use the subelement <data name=... scalar=... /> */
void setScalar(const char name[], SkScalar value) { fMeta.setScalar(name, value); }
void setScalar(const char name[], SkScalar value) { fMeta.setScalar(name, value); }
/** Add/replace the named SkScalar[] field to the event. */
SkScalar* setScalars(const char name[], int count, const SkScalar values[] = NULL) { return fMeta.setScalars(name, count, values); }
/** Add/replace the named string field to the event. In XML use the subelement <data name=... string=... */
void setString(const char name[], const SkString& value) { fMeta.setString(name, value.c_str()); }
void setString(const char name[], const SkString& value) { fMeta.setString(name, value.c_str()); }
/** Add/replace the named string field to the event. In XML use the subelement <data name=... string=... */
void setString(const char name[], const char value[]) { fMeta.setString(name, value); }
void setString(const char name[], const char value[]) { fMeta.setString(name, value); }
/** Add/replace the named pointer field to the event. There is no XML equivalent for this call */
void setPtr(const char name[], void* value) { fMeta.setPtr(name, value); }
void setBool(const char name[], bool value) { fMeta.setBool(name, value); }
void setPtr(const char name[], void* value) { fMeta.setPtr(name, value); }
void setBool(const char name[], bool value) { fMeta.setBool(name, value); }
void setData(const char name[], const void* data, size_t byteCount) {
fMeta.setData(name, data, byteCount);
}
/** Return the underlying metadata object */
SkMetaData& getMetaData() { return fMeta; }
SkMetaData& getMetaData() { return fMeta; }
/** Return the underlying metadata object */
const SkMetaData& getMetaData() const { return fMeta; }
void tron() { SkDEBUGCODE(fDebugTrace = true;) }
void troff() { SkDEBUGCODE(fDebugTrace = false;) }
bool isDebugTrace() const
{
#ifdef SK_DEBUG
return fDebugTrace;
#else
return false;
#endif
}
const SkMetaData& getMetaData() const { return fMeta; }
/** Call this to initialize the event from the specified XML node */
void inflate(const SkDOM&, const SkDOM::Node*);
void inflate(const SkDOM&, const SkDOM::Node*);
SkDEBUGCODE(void dump(const char title[] = NULL);)
/** Post the specified event to the event queue, targeting the specified eventsink, with an optional
delay. The event must be dynamically allocated for this. It cannot be a global or on the stack.
After this call, ownership is transfered to the system, so the caller must not retain
the event's ptr. Returns false if the event could not be posted (which means it will have been deleted).
*/
static bool Post(SkEvent* evt, SkEventSinkID targetID, SkMSec delay = 0);
/** Post the specified event to the event queue, targeting the specified eventsink, to be delivered on/after the
specified millisecond time. The event must be dynamically allocated for this. It cannot be a global or on the stack.
After this call, ownership is transfered to the system, so the caller must not retain
the event's ptr. Returns false if the event could not be posted (which means it will have been deleted).
*/
static bool PostTime(SkEvent* evt, SkEventSinkID targetID, SkMSec time);
///////////////////////////////////////////////////////////////////////////
/**
* Post to the event queue using the event's targetID. If this is 0, then
* false is returned and the event is deleted, otherwise true is returned
* and ownership of the event passes to the event queue.
* Post to the event queue using the event's targetID or target-proc.
*
* The event must be dynamically allocated, as ownership is transferred to
* the event queue. It cannot be allocated on the stack or in a global.
*/
bool post() {
void post() {
return this->postDelay(0);
}
/**
* Post to the event queue using the event's targetID and the specifed
* millisecond delay. If the event's targetID is 0, then false is returned
* and the event is deleted, otherwise true is returned and ownership of
* the event passes to the event queue.
* Post to the event queue using the event's targetID or target-proc and
* the specifed millisecond delay.
*
* The event must be dynamically allocated, as ownership is transferred to
* the event queue. It cannot be allocated on the stack or in a global.
*/
bool postDelay(SkMSec delay);
void postDelay(SkMSec delay);
/**
* Post to the event queue using the event's targetID and the specifed
* millisecond time. If the event's targetID is 0, then false is returned
* and the event is deleted, otherwise true is returned and ownership of
* the event passes to the event queue.
* Post to the event queue using the event's targetID or target-proc.
* The event will be delivered no sooner than the specified millisecond
* time, as measured by SkTime::GetMSecs().
*
* The event must be dynamically allocated, as ownership is transferred to
* the event queue. It cannot be allocated on the stack or in a global.
*/
bool postTime(SkMSec time);
/** Helper method for calling SkEvent::PostTime(this, ...), where the caller specifies a delay.
The real "time" will be computed automatically by sampling the clock and adding its value
to delay.
*/
bool post(SkEventSinkID sinkID, SkMSec delay = 0) {
return SkEvent::Post(this, sinkID, delay);
}
void postTime(SkEventSinkID sinkID, SkMSec time) {
SkEvent::PostTime(this, sinkID, time);
}
void postTime(SkMSec time);
///////////////////////////////////////////////
/** Porting layer must call these functions **/
@ -213,21 +223,21 @@ public:
once before any other event method is called, and should be called after the
call to SkGraphics::Init().
*/
static void Init();
static void Init();
/** Global cleanup function for the SkEvent system. Should be called exactly once after
all event methods have been called, and should be called before calling SkGraphics::Term().
*/
static void Term();
static void Term();
/** Call this to process one event from the queue. If it returns true, there are more events
to process.
*/
static bool ProcessEvent();
static bool ProcessEvent();
/** Call this whenever the requested timer has expired (requested by a call to SetQueueTimer).
It will post any delayed events whose time as "expired" onto the event queue.
It may also call SignalQueueTimer() and SignalNonEmptyQueue().
*/
static void ServiceQueueTimer();
static void ServiceQueueTimer();
/** Return the number of queued events. note that this value may be obsolete
upon return, since another thread may have called ProcessEvent() or
@ -264,17 +274,20 @@ private:
SkMetaData fMeta;
mutable char* fType; // may be characters with low bit set to know that it is not a pointer
uint32_t f32;
// 'there can be only one' (non-zero) between target-id and target-proc
SkEventSinkID fTargetID;
SkDEBUGCODE(bool fDebugTrace;)
Proc fTargetProc;
// these are for our implementation of the event queue
SkMSec fTime;
SkEvent* fNextEvent; // either in the delay or normal event queue
void initialize(const char* type, size_t typeLen);
void initialize(const char* type, size_t typeLen, SkEventSinkID);
static bool Enqueue(SkEvent* evt);
static SkMSec EnqueueTime(SkEvent* evt, SkMSec time);
static SkEvent* Dequeue(SkEventSinkID* targetID);
static SkEvent* Dequeue();
static bool QHasEvents();
};

View File

@ -24,53 +24,66 @@ public:
SkEventSink();
virtual ~SkEventSink();
/** Returns this eventsink's unique ID. Use this to post SkEvents to
this eventsink.
*/
/**
* Returns this eventsink's unique ID. Use this to post SkEvents to
* this eventsink.
*/
SkEventSinkID getSinkID() const { return fID; }
/** Call this to pass an event to this object for processing. Returns true if the
event was handled.
*/
/**
* Call this to pass an event to this object for processing. Returns true if the
* event was handled.
*/
bool doEvent(const SkEvent&);
/** Returns true if the sink (or one of its subclasses) understands the event as a query.
If so, the sink may modify the event to communicate its "answer".
*/
bool doQuery(SkEvent* query);
/** Add sinkID to the list of listeners, to receive events from calls to sendToListeners()
and postToListeners(). If sinkID already exists in the listener list, no change is made.
*/
void addListenerID(SkEventSinkID sinkID);
/** Copy listeners from one event sink to another, typically from parent to child.
@param from the event sink to copy the listeners from
*/
/**
* Add sinkID to the list of listeners, to receive events from calls to sendToListeners()
* and postToListeners(). If sinkID already exists in the listener list, no change is made.
*/
void addListenerID(SkEventSinkID sinkID);
/**
* Copy listeners from one event sink to another, typically from parent to child.
* @param from the event sink to copy the listeners from
*/
void copyListeners(const SkEventSink& from);
/** Remove sinkID from the list of listeners. If sinkID does not appear in the list,
no change is made.
*/
void removeListenerID(SkEventSinkID);
/** Returns true if there are 1 or more listeners attached to this eventsink
*/
bool hasListeners() const;
/** Posts a copy of evt to each of the eventsinks in the lisener list.
*/
void postToListeners(const SkEvent& evt, SkMSec delay = 0);
/**
* Remove sinkID from the list of listeners. If sinkID does not appear in the list,
* no change is made.
*/
void removeListenerID(SkEventSinkID);
/**
* Returns true if there are 1 or more listeners attached to this eventsink
*/
bool hasListeners() const;
/**
* Posts a copy of evt to each of the eventsinks in the lisener list.
* This ignores the targetID and target proc in evt.
*/
void postToListeners(const SkEvent& evt, SkMSec delay = 0);
enum EventResult {
kHandled_EventResult, //!< the eventsink returned true from its doEvent method
kNotHandled_EventResult, //!< the eventsink returned false from its doEvent method
kSinkNotFound_EventResult //!< no matching eventsink was found for the event's getSink().
};
/** DoEvent handles searching for an eventsink object that matches the targetID.
If one is found, it calls the sink's doEvent method, returning
either kHandled_EventResult or kNotHandled_EventResult. If no matching
eventsink is found, kSinkNotFound_EventResult is returned.
*/
static EventResult DoEvent(const SkEvent&, SkEventSinkID targetID);
/** Returns the matching eventsink, or null if not found
*/
/**
* DoEvent handles dispatching the event to its target ID or proc.
*/
static EventResult DoEvent(const SkEvent&);
/**
* Returns the matching eventsink, or null if not found
*/
static SkEventSink* FindSink(SkEventSinkID);
protected:

View File

@ -64,7 +64,9 @@ public:
//Post event associated with the menu item to target, any changes to the
//associated event must be made prior to calling this method.
void postEvent() const { (new SkEvent(*(fEvent)))->post(fTarget); }
void postEvent() const {
(new SkEvent(*(fEvent)))->setTargetID(fTarget)->post();
}
//Helper functions for predefined types
void postEventWithBool(bool value) const; //For Switch

View File

@ -162,10 +162,6 @@ public:
*/
SkView* sendQueryToParents(SkEvent*);
/** Depricated helper function. Just call event->post(sinkID, delay);
*/
bool postEvent(SkEvent* evt, SkEventSinkID sinkID, SkMSec delay) { return evt->post(sinkID, delay); }
// View hierarchy management
/** Return the view's parent, or null if it has none. This does not affect the parent's reference count. */

View File

@ -156,8 +156,7 @@ private:
static const char view_inval_msg[] = "view-inval-msg";
void SampleWindow::postInvalDelay() {
SkEvent* evt = new SkEvent(view_inval_msg);
evt->post(this->getSinkID(), 1);
(new SkEvent(view_inval_msg, this->getSinkID()))->postDelay(1);
}
static bool isInvalEvent(const SkEvent& evt) {
@ -1002,8 +1001,7 @@ int SampleWindow::sampleCount() {
void SampleWindow::postAnimatingEvent() {
if (fAnimating) {
SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
evt->post(this->getSinkID(), ANIMATING_DELAY);
(new SkEvent(ANIMATING_EVENTTYPE, this->getSinkID()))->postDelay(ANIMATING_DELAY);
}
}
@ -1416,6 +1414,7 @@ void SampleWindow::loadView(SkView* view) {
if (NULL == view) {
view = create_overview(fSamples.count(), fSamples.begin());
}
view->setVisibleP(true);
view->setClipToBounds(false);
this->attachChildToFront(view)->unref();

View File

@ -96,7 +96,7 @@ protected:
private:
void postNextGM() {
(new SkEvent("next-gm"))->post(this->getSinkID(), 1500);
(new SkEvent("next-gm", this->getSinkID()))->postDelay(1500);
}
typedef SampleView INHERITED;

View File

@ -173,7 +173,7 @@ private:
#define INVAL_ALL_TYPE "inval-all"
void delayInval(SkMSec delay) {
(new SkEvent(INVAL_ALL_TYPE))->post(this->getSinkID(), delay);
(new SkEvent(INVAL_ALL_TYPE, this->getSinkID()))->postDelay(delay);
}
virtual bool onEvent(const SkEvent& evt) {

View File

@ -95,6 +95,30 @@ protected:
virtual void onDrawContent(SkCanvas* canvas) {
canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
if (false) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setTextSize(50);
paint.setTypeface(SkTypeface::CreateFromName("Arial Unicode MS", SkTypeface::kNormal));
SkSafeUnref(paint.getTypeface());
char buffer[10];
size_t len = SkUTF8_FromUnichar(0x8500, buffer);
canvas->drawText(buffer, len, 40, 40, paint);
return;
}
if (true) {
SkPaint paint;
paint.setAntiAlias(true);
SkRect r0 = { 0, 0, 10.5f, 20 };
SkRect r1 = { 10.5f, 10, 20, 30 };
paint.setColor(SK_ColorRED);
canvas->drawRect(r0, paint);
paint.setColor(SK_ColorBLUE);
canvas->drawRect(r1, paint);
return;
}
const struct {
SkXfermode::Mode fMode;
const char* fLabel;

View File

@ -121,9 +121,11 @@ extern "C" {
void SkAnimateMaker::delayEnable(SkApply* apply, SkMSec time) {
int index = fDelayed.find(apply);
if (index < 0)
if (index < 0) {
*fDelayed.append() = apply;
(new SkEvent(SK_EventType_Delay))->postTime(fAnimator->getSinkID(), time);
}
(new SkEvent(SK_EventType_Delay, fAnimator->getSinkID()))->postTime(time);
}
void SkAnimateMaker::deleteMembers() {

View File

@ -479,7 +479,7 @@ void SkAnimator::onEventPost(SkEvent* evt, SkEventSinkID sinkID)
#else
SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
#endif
SkEvent::Post(evt, sinkID);
evt->setTargetID(sinkID)->post();
}
void SkAnimator::onEventPostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time)
@ -493,7 +493,7 @@ void SkAnimator::onEventPostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time
#else
SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
#endif
SkEvent::PostTime(evt, sinkID, time);
evt->setTargetID(sinkID)->postTime(time);
}
void SkAnimator::reset() {

View File

@ -204,8 +204,7 @@ void SkOSWindow::updateSize()
void SkOSWindow::onHandleInval(const SkIRect& r)
{
SkEvent* evt = new SkEvent("inval-imageview");
evt->post(this->getSinkID());
(new SkEvent("inval-imageview", this->getSinkID()))->post();
}
bool SkOSWindow::onEvent(const SkEvent& evt) {

View File

@ -9,21 +9,22 @@
#include "SkEvent.h"
void SkEvent::initialize(const char* type, size_t typeLen) {
void SkEvent::initialize(const char* type, size_t typeLen,
SkEventSinkID targetID) {
fType = NULL;
setType(type, typeLen);
f32 = 0;
fTargetID = targetID;
fTargetProc = NULL;
#ifdef SK_DEBUG
fTargetID = 0;
fTime = 0;
fNextEvent = NULL;
#endif
SkDEBUGCODE(fDebugTrace = false;)
}
SkEvent::SkEvent()
{
initialize("", 0);
initialize("", 0, 0);
}
SkEvent::SkEvent(const SkEvent& src)
@ -33,15 +34,15 @@ SkEvent::SkEvent(const SkEvent& src)
setType(src.fType);
}
SkEvent::SkEvent(const SkString& type)
SkEvent::SkEvent(const SkString& type, SkEventSinkID targetID)
{
initialize(type.c_str(), type.size());
initialize(type.c_str(), type.size(), targetID);
}
SkEvent::SkEvent(const char type[])
SkEvent::SkEvent(const char type[], SkEventSinkID targetID)
{
SkASSERT(type);
initialize(type, strlen(type));
initialize(type, strlen(type), targetID);
}
SkEvent::~SkEvent()
@ -288,90 +289,50 @@ static SkGlobals::Rec* create_globals()
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::postDelay(SkMSec delay) {
return SkEvent::Post(this, this->getTargetID(), delay);
}
bool SkEvent::postTime(SkMSec time) {
SkEventSinkID target = this->getTargetID();
if (target) {
return SkEvent::PostTime(this, target, time);
} else {
void SkEvent::postDelay(SkMSec delay) {
if (!fTargetID && !fTargetProc) {
delete this;
return false;
return;
}
if (delay) {
this->postTime(SkTime::GetMSecs() + delay);
return;
}
SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
globals.fEventMutex.acquire();
bool wasEmpty = SkEvent::Enqueue(this);
globals.fEventMutex.release();
// call outside of us holding the mutex
if (wasEmpty) {
SkEvent::SignalNonEmptyQueue();
}
}
bool SkEvent::Enqueue(SkEvent* evt)
{
void SkEvent::postTime(SkMSec time) {
if (!fTargetID && !fTargetProc) {
delete this;
return;
}
SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
globals.fEventMutex.acquire();
SkMSec queueDelay = SkEvent::EnqueueTime(this, time);
globals.fEventMutex.release();
// call outside of us holding the mutex
if ((int32_t)queueDelay != ~0) {
SkEvent::SignalQueueTimer(queueDelay);
}
}
bool SkEvent::Enqueue(SkEvent* evt) {
SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
// gEventMutex acquired by caller
@ -387,37 +348,29 @@ bool SkEvent::Enqueue(SkEvent* evt)
evt->fNextEvent = NULL;
SkDEBUGCODE(++globals.fEventCounter);
// SkDebugf("Enqueue: count=%d\n", gEventCounter);
return wasEmpty;
}
SkEvent* SkEvent::Dequeue(SkEventSinkID* sinkID)
{
SkEvent* SkEvent::Dequeue() {
SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
globals.fEventMutex.acquire();
SkEvent* evt = globals.fEventQHead;
if (evt)
{
if (evt) {
SkDEBUGCODE(--globals.fEventCounter);
if (sinkID)
*sinkID = evt->fTargetID;
globals.fEventQHead = evt->fNextEvent;
if (globals.fEventQHead == NULL)
if (globals.fEventQHead == NULL) {
globals.fEventQTail = NULL;
}
}
globals.fEventMutex.release();
// SkDebugf("Dequeue: count=%d\n", gEventCounter);
return evt;
}
bool SkEvent::QHasEvents()
{
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
@ -428,60 +381,49 @@ bool SkEvent::QHasEvents()
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
SkMSec SkEvent::EnqueueTime(SkEvent* evt, SkMSec time) {
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))
while (curr) {
if (SkMSec_LT(time, curr->fTime)) {
break;
}
prev = curr;
curr = curr->fNextEvent;
}
evt->fTime = time;
evt->fNextEvent = curr;
if (prev == NULL)
if (prev == NULL) {
globals.fDelayQHead = evt;
else
} else {
prev->fNextEvent = evt;
}
SkMSec delay = globals.fDelayQHead->fTime - SkTime::GetMSecs();
if ((int32_t)delay <= 0)
if ((int32_t)delay <= 0) {
delay = 1;
}
return delay;
}
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#include "SkEventSink.h"
bool SkEvent::ProcessEvent()
{
SkEventSinkID sinkID;
SkEvent* evt = SkEvent::Dequeue(&sinkID);
bool SkEvent::ProcessEvent() {
SkEvent* evt = SkEvent::Dequeue();
SkAutoTDelete<SkEvent> autoDelete(evt);
bool again = false;
bool again = false;
EVENT_LOGN("ProcessEvent", (int32_t)evt);
if (evt)
{
(void)SkEventSink::DoEvent(*evt, sinkID);
if (evt) {
(void)SkEventSink::DoEvent(*evt);
again = SkEvent::QHasEvents();
}
return again;

View File

@ -213,58 +213,33 @@ bool SkEventSink::hasListeners() const
return this->findTagList(kListeners_SkTagList) != NULL;
}
void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay)
{
void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay) {
SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
if (list)
{
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);
while (iter < stop) {
SkEvent* copy = SkNEW_ARGS(SkEvent, (evt));
copy->setTargetID(*iter++)->postDelay(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
SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt) {
SkEvent::Proc proc = evt.getTargetProc();
if (proc) {
return proc(evt) ? kHandled_EventResult : kNotHandled_EventResult;
}
SkEventSink* sink = SkEventSink::FindSink(evt.getTargetID());
if (sink) {
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;
}
return kSinkNotFound_EventResult;
}
SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)