michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkDisplayPost.h" michael@0: #include "SkAnimateMaker.h" michael@0: #include "SkAnimator.h" michael@0: #include "SkDisplayMovie.h" michael@0: #include "SkPostParts.h" michael@0: #include "SkScript.h" michael@0: #ifdef SK_DEBUG michael@0: #include "SkDump.h" michael@0: #include "SkTime.h" michael@0: #endif michael@0: michael@0: enum SkPost_Properties { michael@0: SK_PROPERTY(target), michael@0: SK_PROPERTY(type) michael@0: }; michael@0: michael@0: #if SK_USE_CONDENSED_INFO == 0 michael@0: michael@0: const SkMemberInfo SkPost::fInfo[] = { michael@0: SK_MEMBER(delay, MSec), michael@0: // SK_MEMBER(initialized, Boolean), michael@0: SK_MEMBER(mode, EventMode), michael@0: SK_MEMBER(sink, String), michael@0: SK_MEMBER_PROPERTY(target, String), michael@0: SK_MEMBER_PROPERTY(type, String) michael@0: }; michael@0: michael@0: #endif michael@0: michael@0: DEFINE_GET_MEMBER(SkPost); michael@0: michael@0: SkPost::SkPost() : delay(0), /*initialized(SkBool(-1)), */ mode(kImmediate), fMaker(NULL), michael@0: fSinkID(0), fTargetMaker(NULL), fChildHasID(false), fDirty(false) { michael@0: } michael@0: michael@0: SkPost::~SkPost() { michael@0: for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) michael@0: delete *part; michael@0: } michael@0: michael@0: bool SkPost::addChild(SkAnimateMaker& , SkDisplayable* child) { michael@0: SkASSERT(child && child->isDataInput()); michael@0: SkDataInput* part = (SkDataInput*) child; michael@0: *fParts.append() = part; michael@0: return true; michael@0: } michael@0: michael@0: bool SkPost::childrenNeedDisposing() const { michael@0: return false; michael@0: } michael@0: michael@0: void SkPost::dirty() { michael@0: fDirty = true; michael@0: } michael@0: michael@0: #ifdef SK_DUMP_ENABLED michael@0: void SkPost::dump(SkAnimateMaker* maker) { michael@0: dumpBase(maker); michael@0: SkString* eventType = new SkString(); michael@0: fEvent.getType(eventType); michael@0: if (eventType->equals("user")) { michael@0: const char* target = fEvent.findString("id"); michael@0: SkDebugf("target=\"%s\" ", target); michael@0: } michael@0: else michael@0: SkDebugf("type=\"%s\" ", eventType->c_str()); michael@0: delete eventType; michael@0: michael@0: if (delay > 0) { michael@0: SkDebugf("delay=\"%g\" ", SkScalarToFloat(SkScalarDiv(delay, 1000))); michael@0: } michael@0: // if (initialized == false) michael@0: // SkDebugf("(uninitialized) "); michael@0: SkString string; michael@0: SkDump::GetEnumString(SkType_EventMode, mode, &string); michael@0: if (!string.equals("immediate")) michael@0: SkDebugf("mode=\"%s\" ", string.c_str()); michael@0: // !!! could enhance this to search through make hierarchy to show name of sink michael@0: if (sink.size() > 0) { michael@0: SkDebugf("sink=\"%s\" sinkID=\"%d\" ", sink.c_str(), fSinkID); michael@0: } else if (fSinkID != maker->getAnimator()->getSinkID() && fSinkID != 0) { michael@0: SkDebugf("sinkID=\"%d\" ", fSinkID); michael@0: } michael@0: const SkMetaData& meta = fEvent.getMetaData(); michael@0: SkMetaData::Iter iter(meta); michael@0: SkMetaData::Type type; michael@0: int number; michael@0: const char* name; michael@0: bool closedYet = false; michael@0: SkDisplayList::fIndent += 4; michael@0: //this seems to work, but kinda hacky michael@0: //for some reason the last part is id, which i don't want michael@0: //and the parts seem to be in the reverse order from the one in which we find the michael@0: //data itself michael@0: //SkDataInput** ptr = fParts.end(); michael@0: //SkDataInput* data; michael@0: //const char* ID; michael@0: while ((name = iter.next(&type, &number)) != NULL) { michael@0: //ptr--; michael@0: if (strcmp(name, "id") == 0) michael@0: continue; michael@0: if (closedYet == false) { michael@0: SkDebugf(">\n"); michael@0: closedYet = true; michael@0: } michael@0: //data = *ptr; michael@0: //if (data->id) michael@0: // ID = data->id; michael@0: //else michael@0: // ID = ""; michael@0: SkDebugf("%*s\n"); michael@0: //ptr++; michael@0: /* perhaps this should only be done in the case of a pointer? michael@0: SkDisplayable* displayable; michael@0: if (maker->find(name, &displayable)) michael@0: displayable->dump(maker); michael@0: else michael@0: SkDebugf("\n");*/ michael@0: } michael@0: SkDisplayList::fIndent -= 4; michael@0: if (closedYet) michael@0: dumpEnd(maker); michael@0: else michael@0: SkDebugf("/>\n"); michael@0: michael@0: } michael@0: #endif michael@0: michael@0: bool SkPost::enable(SkAnimateMaker& maker ) { michael@0: if (maker.hasError()) michael@0: return true; michael@0: if (fDirty) { michael@0: if (sink.size() > 0) michael@0: findSinkID(); michael@0: if (fChildHasID) { michael@0: SkString preserveID(fEvent.findString("id")); michael@0: fEvent.getMetaData().reset(); michael@0: if (preserveID.size() > 0) michael@0: fEvent.setString("id", preserveID); michael@0: for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) { michael@0: if ((*part)->add()) michael@0: maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingDataToPost); michael@0: } michael@0: } michael@0: fDirty = false; michael@0: } michael@0: #ifdef SK_DUMP_ENABLED michael@0: if (maker.fDumpPosts) { michael@0: SkDebugf("post enable: "); michael@0: dump(&maker); michael@0: } michael@0: #if defined SK_DEBUG_ANIMATION_TIMING michael@0: SkString debugOut; michael@0: SkMSec time = maker.getAppTime(); michael@0: debugOut.appendS32(time - maker.fDebugTimeBase); michael@0: debugOut.append(" post id="); michael@0: debugOut.append(_id); michael@0: debugOut.append(" enable="); michael@0: debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase); michael@0: debugOut.append(" delay="); michael@0: debugOut.appendS32(delay); michael@0: #endif michael@0: #endif michael@0: // SkMSec adjustedDelay = maker.adjustDelay(maker.fEnableTime, delay); michael@0: SkMSec futureTime = maker.fEnableTime + delay; michael@0: fEvent.setFast32(futureTime); michael@0: #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING michael@0: debugOut.append(" future="); michael@0: debugOut.appendS32(futureTime - maker.fDebugTimeBase); michael@0: SkDebugf("%s\n", debugOut.c_str()); michael@0: #endif michael@0: SkEventSinkID targetID = fSinkID; michael@0: bool isAnimatorEvent = true; michael@0: SkAnimator* anim = maker.getAnimator(); michael@0: if (targetID == 0) { michael@0: isAnimatorEvent = fEvent.findString("id") != NULL; michael@0: if (isAnimatorEvent) michael@0: targetID = anim->getSinkID(); michael@0: else if (maker.fHostEventSinkID) michael@0: targetID = maker.fHostEventSinkID; michael@0: else michael@0: return true; michael@0: } else michael@0: anim = fTargetMaker->getAnimator(); michael@0: if (delay == 0) { michael@0: if (isAnimatorEvent && mode == kImmediate) michael@0: fTargetMaker->doEvent(fEvent); michael@0: else michael@0: anim->onEventPost(new SkEvent(fEvent), targetID); michael@0: } else michael@0: anim->onEventPostTime(new SkEvent(fEvent), targetID, futureTime); michael@0: return true; michael@0: } michael@0: michael@0: void SkPost::findSinkID() { michael@0: // get the next delimiter '.' if any michael@0: fTargetMaker = fMaker; michael@0: const char* ch = sink.c_str(); michael@0: do { michael@0: const char* end = strchr(ch, '.'); michael@0: size_t len = end ? (size_t) (end - ch) : strlen(ch); michael@0: SkDisplayable* displayable = NULL; michael@0: if (SK_LITERAL_STR_EQUAL("parent", ch, len)) { michael@0: if (fTargetMaker->fParentMaker) michael@0: fTargetMaker = fTargetMaker->fParentMaker; michael@0: else { michael@0: fTargetMaker->setErrorCode(SkDisplayXMLParserError::kNoParentAvailable); michael@0: return; michael@0: } michael@0: } else { michael@0: fTargetMaker->find(ch, len, &displayable); michael@0: if (displayable == NULL || displayable->getType() != SkType_Movie) { michael@0: fTargetMaker->setErrorCode(SkDisplayXMLParserError::kExpectedMovie); michael@0: return; michael@0: } michael@0: SkDisplayMovie* movie = (SkDisplayMovie*) displayable; michael@0: fTargetMaker = movie->fMovie.fMaker; michael@0: } michael@0: if (end == NULL) michael@0: break; michael@0: ch = ++end; michael@0: } while (true); michael@0: SkAnimator* anim = fTargetMaker->getAnimator(); michael@0: fSinkID = anim->getSinkID(); michael@0: } michael@0: michael@0: bool SkPost::hasEnable() const { michael@0: return true; michael@0: } michael@0: michael@0: void SkPost::onEndElement(SkAnimateMaker& maker) { michael@0: fTargetMaker = fMaker = &maker; michael@0: if (fChildHasID == false) { michael@0: for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) michael@0: delete *part; michael@0: fParts.reset(); michael@0: } michael@0: } michael@0: michael@0: void SkPost::setChildHasID() { michael@0: fChildHasID = true; michael@0: } michael@0: michael@0: bool SkPost::setProperty(int index, SkScriptValue& value) { michael@0: SkASSERT(value.fType == SkType_String); michael@0: SkString* string = value.fOperand.fString; michael@0: switch(index) { michael@0: case SK_PROPERTY(target): { michael@0: fEvent.setType("user"); michael@0: fEvent.setString("id", *string); michael@0: mode = kImmediate; michael@0: } break; michael@0: case SK_PROPERTY(type): michael@0: fEvent.setType(*string); michael@0: break; michael@0: default: michael@0: SkASSERT(0); michael@0: return false; michael@0: } michael@0: return true; michael@0: }