|  |  | 
|  | /* | 
|  | * 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 "SkDisplayEvent.h" | 
|  | #include "SkAnimateMaker.h" | 
|  | #include "SkDisplayApply.h" | 
|  | #include "SkDisplayInput.h" | 
|  | #include "SkDisplayList.h" | 
|  | #ifdef SK_DEBUG | 
|  | #include "SkDump.h" | 
|  | #endif | 
|  | #include "SkEvent.h" | 
|  | #include "SkDisplayInput.h" | 
|  | #include "SkKey.h" | 
|  | #include "SkMetaData.h" | 
|  | #include "SkScript.h" | 
|  | #include "SkUtils.h" | 
|  |  | 
|  | enum SkDisplayEvent_Properties { | 
|  | SK_PROPERTY(key), | 
|  | SK_PROPERTY(keys) | 
|  | }; | 
|  |  | 
|  | #if SK_USE_CONDENSED_INFO == 0 | 
|  |  | 
|  | const SkMemberInfo SkDisplayEvent::fInfo[] = { | 
|  | SK_MEMBER(code, EventCode), | 
|  | SK_MEMBER(disable, Boolean), | 
|  | SK_MEMBER_PROPERTY(key, String), // a single key (also last key pressed) | 
|  | SK_MEMBER_PROPERTY(keys, String), // a single key or dash-delimited range of keys | 
|  | SK_MEMBER(kind, EventKind), | 
|  | SK_MEMBER(target, String), | 
|  | SK_MEMBER(x, Float), | 
|  | SK_MEMBER(y, Float) | 
|  | }; | 
|  |  | 
|  | #endif | 
|  |  | 
|  | DEFINE_GET_MEMBER(SkDisplayEvent); | 
|  |  | 
|  | SkDisplayEvent::SkDisplayEvent() : code((SkKey) -1), disable(false), | 
|  | kind(kUser), x(0), y(0), fLastCode((SkKey) -1), fMax((SkKey) -1), fTarget(nullptr) { | 
|  | } | 
|  |  | 
|  | SkDisplayEvent::~SkDisplayEvent() { | 
|  | deleteMembers(); | 
|  | } | 
|  |  | 
|  | bool SkDisplayEvent::addChild(SkAnimateMaker& , SkDisplayable* child) { | 
|  | *fChildren.append() = child; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool SkDisplayEvent::contains(SkDisplayable* match) { | 
|  | for (int index = 0; index < fChildren.count(); index++) { | 
|  | if (fChildren[index] == match || fChildren[index]->contains(match)) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | SkDisplayable* SkDisplayEvent::contains(const SkString& match) { | 
|  | for (int index = 0; index < fChildren.count(); index++) { | 
|  | SkDisplayable* child = fChildren[index]; | 
|  | if (child->contains(match)) | 
|  | return child; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | void SkDisplayEvent::deleteMembers() { | 
|  | for (int index = 0; index < fChildren.count(); index++) { | 
|  | SkDisplayable* evt = fChildren[index]; | 
|  | delete evt; | 
|  | } | 
|  | } | 
|  |  | 
|  | #ifdef SK_DUMP_ENABLED | 
|  | void SkDisplayEvent::dumpEvent(SkAnimateMaker* maker) { | 
|  | dumpBase(maker); | 
|  | SkString str; | 
|  | SkDump::GetEnumString(SkType_EventKind, kind, &str); | 
|  | SkDebugf("kind=\"%s\" ", str.c_str()); | 
|  | if (kind == SkDisplayEvent::kKeyPress || kind == SkDisplayEvent::kKeyPressUp) { | 
|  | if (code >= 0) | 
|  | SkDump::GetEnumString(SkType_EventCode, code, &str); | 
|  | else | 
|  | str.set("none"); | 
|  | SkDebugf("code=\"%s\" ", str.c_str()); | 
|  | } | 
|  | if (kind == SkDisplayEvent::kKeyChar) { | 
|  | if (fMax != (SkKey) -1 && fMax != code) | 
|  | SkDebugf("keys=\"%c - %c\" ", code, fMax); | 
|  | else | 
|  | SkDebugf("key=\"%c\" ", code); | 
|  | } | 
|  | if (fTarget != nullptr) { | 
|  | SkDebugf("target=\"%s\" ", fTarget->id); | 
|  | } | 
|  | if (kind >= SkDisplayEvent::kMouseDown && kind <= SkDisplayEvent::kMouseUp) { | 
|  | SkDebugf("x=\"%g\" y=\"%g\" ", SkScalarToFloat(x), SkScalarToFloat(y)); | 
|  | } | 
|  | if (disable) | 
|  | SkDebugf("disable=\"true\" "); | 
|  | SkDebugf("/>\n"); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool SkDisplayEvent::enableEvent(SkAnimateMaker& maker) | 
|  | { | 
|  | maker.fActiveEvent = this; | 
|  | if (fChildren.count() == 0) | 
|  | return false; | 
|  | if (disable) | 
|  | return false; | 
|  | #ifdef SK_DUMP_ENABLED | 
|  | if (maker.fDumpEvents) { | 
|  | SkDebugf("enable: "); | 
|  | dumpEvent(&maker); | 
|  | } | 
|  | #endif | 
|  | SkDisplayList& displayList = maker.fDisplayList; | 
|  | for (int index = 0; index < fChildren.count(); index++) { | 
|  | SkDisplayable* displayable = fChildren[index]; | 
|  | if (displayable->isGroup()) { | 
|  | SkTDDrawableArray* parentList = displayList.getDrawList(); | 
|  | *parentList->append() = (SkADrawable*) displayable;  // make it findable before children are enabled | 
|  | } | 
|  | if (displayable->enable(maker)) | 
|  | continue; | 
|  | if (maker.hasError()) | 
|  | return true; | 
|  | if (displayable->isDrawable() == false) | 
|  | return true;    // error | 
|  | SkADrawable* drawable = (SkADrawable*) displayable; | 
|  | SkTDDrawableArray* parentList = displayList.getDrawList(); | 
|  | *parentList->append() = drawable; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool SkDisplayEvent::getProperty(int index, SkScriptValue* value) const { | 
|  | switch (index) { | 
|  | case SK_PROPERTY(key): | 
|  | case SK_PROPERTY(keys): { | 
|  | value->fType = SkType_String; | 
|  | char scratch[8]; | 
|  | SkKey convert = index == SK_PROPERTY(keys) ? code : fLastCode; | 
|  | size_t size = convert > 0 ? SkUTF8_FromUnichar(convert, scratch) : 0; | 
|  | fKeyString.set(scratch, size); | 
|  | value->fOperand.fString = &fKeyString; | 
|  | if (index != SK_PROPERTY(keys) || fMax == (SkKey) -1 || fMax == code) | 
|  | break; | 
|  | value->fOperand.fString->append("-"); | 
|  | size = SkUTF8_FromUnichar(fMax, scratch); | 
|  | value->fOperand.fString->append(scratch, size); | 
|  | } break; | 
|  | default: | 
|  | SkASSERT(0); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void SkDisplayEvent::onEndElement(SkAnimateMaker& maker) | 
|  | { | 
|  | if (kind == kUser) | 
|  | return; | 
|  | maker.fEvents.addEvent(this); | 
|  | if (kind == kOnEnd) { | 
|  | SkDEBUGCODE(bool found = ) maker.find(target.c_str(), &fTarget); | 
|  | SkASSERT(found); | 
|  | SkASSERT(fTarget && fTarget->isAnimate()); | 
|  | SkAnimateBase* animate = (SkAnimateBase*) fTarget; | 
|  | animate->setHasEndEvent(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SkDisplayEvent::populateInput(SkAnimateMaker& maker, const SkEvent& fEvent) { | 
|  | const SkMetaData& meta = fEvent.getMetaData(); | 
|  | SkMetaData::Iter iter(meta); | 
|  | SkMetaData::Type    type; | 
|  | int number; | 
|  | const char* name; | 
|  | while ((name = iter.next(&type, &number)) != nullptr) { | 
|  | if (name[0] == '\0') | 
|  | continue; | 
|  | SkDisplayable* displayable; | 
|  | SkInput* input; | 
|  | for (int index = 0; index < fChildren.count(); index++) { | 
|  | displayable = fChildren[index]; | 
|  | if (displayable->getType() != SkType_Input) | 
|  | continue; | 
|  | input = (SkInput*) displayable; | 
|  | if (input->name.equals(name)) | 
|  | goto found; | 
|  | } | 
|  | if (!maker.find(name, &displayable) || displayable->getType() != SkType_Input) | 
|  | continue; | 
|  | input = (SkInput*) displayable; | 
|  | found: | 
|  | switch (type) { | 
|  | case SkMetaData::kS32_Type: | 
|  | meta.findS32(name, &input->fInt); | 
|  | break; | 
|  | case SkMetaData::kScalar_Type: | 
|  | meta.findScalar(name, &input->fFloat); | 
|  | break; | 
|  | case SkMetaData::kPtr_Type: | 
|  | SkASSERT(0); | 
|  | break; // !!! not handled for now | 
|  | case SkMetaData::kString_Type: | 
|  | input->string.set(meta.findString(name)); | 
|  | break; | 
|  | default: | 
|  | SkASSERT(0); | 
|  | } | 
|  | } | 
|  | // re-evaluate all animators that may have built their values from input strings | 
|  | for (SkDisplayable** childPtr = fChildren.begin(); childPtr < fChildren.end(); childPtr++) { | 
|  | SkDisplayable* displayable = *childPtr; | 
|  | if (displayable->isApply() == false) | 
|  | continue; | 
|  | SkApply* apply = (SkApply*) displayable; | 
|  | apply->refresh(maker); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool SkDisplayEvent::setProperty(int index, SkScriptValue& value) { | 
|  | SkASSERT(index == SK_PROPERTY(key) || index == SK_PROPERTY(keys)); | 
|  | SkASSERT(value.fType == SkType_String); | 
|  | SkString* string = value.fOperand.fString; | 
|  | const char* chars = string->c_str(); | 
|  | int count = SkUTF8_CountUnichars(chars); | 
|  | SkASSERT(count >= 1); | 
|  | code = (SkKey) SkUTF8_NextUnichar(&chars); | 
|  | fMax = code; | 
|  | SkASSERT(count == 1 || index == SK_PROPERTY(keys)); | 
|  | if (--count > 0) { | 
|  | SkASSERT(*chars == '-'); | 
|  | chars++; | 
|  | fMax = (SkKey) SkUTF8_NextUnichar(&chars); | 
|  | SkASSERT(fMax >= code); | 
|  | } | 
|  | return true; | 
|  | } |