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