/*
* 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 "SkAnimateBase.h"
#include "SkAnimateMaker.h"
#include "SkAnimateProperties.h"
#include "SkAnimatorScript.h"
#include "SkDisplayApply.h"
#include "SkADrawable.h"
#if SK_USE_CONDENSED_INFO == 0
const SkMemberInfo SkAnimateBase::fInfo[] = {
SK_MEMBER(begin, MSec),
SK_MEMBER_ARRAY(blend, Float),
SK_MEMBER(dur, MSec),
SK_MEMBER_PROPERTY(dynamic, Boolean),
SK_MEMBER(field, String), // name of member info in target
SK_MEMBER(formula, DynamicString),
SK_MEMBER(from, DynamicString),
SK_MEMBER(lval, DynamicString),
SK_MEMBER_PROPERTY(mirror, Boolean),
SK_MEMBER(repeat, Float),
SK_MEMBER_PROPERTY(reset, Boolean),
SK_MEMBER_PROPERTY(step, Int),
SK_MEMBER(target, DynamicString),
SK_MEMBER(to, DynamicString),
SK_MEMBER_PROPERTY(values, DynamicString)
};
#endif
DEFINE_GET_MEMBER(SkAnimateBase);
SkAnimateBase::SkAnimateBase() : begin(0), dur(1), repeat(SK_Scalar1),
fApply(nullptr), fFieldInfo(nullptr), fFieldOffset(0), fStart((SkMSec) -1), fTarget(nullptr),
fChanged(0), fDelayed(0), fDynamic(0), fHasEndEvent(0), fHasValues(0),
fMirror(0), fReset(0), fResetPending(0), fTargetIsScope(0) {
blend.setCount(1);
blend[0] = SK_Scalar1;
}
SkAnimateBase::~SkAnimateBase() {
SkDisplayTypes type = fValues.getType();
if (type == SkType_String || type == SkType_DynamicString) {
SkASSERT(fValues.count() == 1);
delete fValues[0].fString;
}
}
int SkAnimateBase::components() {
return 1;
}
SkDisplayable* SkAnimateBase::deepCopy(SkAnimateMaker* maker) {
SkAnimateBase* result = (SkAnimateBase*) INHERITED::deepCopy(maker);
result->fApply = fApply;
result->fFieldInfo =fFieldInfo;
result->fHasValues = false;
return result;
}
void SkAnimateBase::dirty() {
fChanged = true;
}
#ifdef SK_DUMP_ENABLED
void SkAnimateBase::dump(SkAnimateMaker* maker) {
dumpBase(maker);
if (target.size() > 0)
SkDebugf("target=\"%s\" ", target.c_str());
else if (fTarget && strcmp(fTarget->id, ""))
SkDebugf("target=\"%s\" ", fTarget->id);
if (lval.size() > 0)
SkDebugf("lval=\"%s\" ", lval.c_str());
if (field.size() > 0)
SkDebugf("field=\"%s\" ", field.c_str());
else if (fFieldInfo)
SkDebugf("field=\"%s\" ", fFieldInfo->fName);
if (formula.size() > 0)
SkDebugf("formula=\"%s\" ", formula.c_str());
else {
if (from.size() > 0)
SkDebugf("from=\"%s\" ", from.c_str());
SkDebugf("to=\"%s\" ", to.c_str());
}
if (begin != 0) {
SkDebugf("begin=\"%g\" ", begin * 0.001);
}
}
#endif
SkDisplayable* SkAnimateBase::getParent() const {
return (SkDisplayable*) fApply;
}
bool SkAnimateBase::getProperty(int index, SkScriptValue* value) const {
int boolResult;
switch (index) {
case SK_PROPERTY(dynamic):
boolResult = fDynamic;
goto returnBool;
case SK_PROPERTY(mirror):
boolResult = fMirror;
goto returnBool;
case SK_PROPERTY(reset):
boolResult = fReset;
returnBool:
value->fOperand.fS32 = SkToBool(boolResult);
value->fType = SkType_Boolean;
break;
case SK_PROPERTY(step):
if (fApply == nullptr)
return false; // !!! notify there's an error?
fApply->getStep(value);
break;
case SK_PROPERTY(values):
value->fOperand.fString = (SkString*) &to;
value->fType = SkType_String;
break;
default:
SkASSERT(0);
return false;
}
return true;
}
bool SkAnimateBase::hasExecute() const
{
return false;
}
void SkAnimateBase::onEndElement(SkAnimateMaker& maker) {
fChanged = false;
setTarget(maker);
if (field.size()) {
SkASSERT(fTarget);
fFieldInfo = fTarget->getMember(field.c_str());
field.reset();
}
if (lval.size()) {
// lval must be of the form x[y]
const char* lvalStr = lval.c_str();
const char* arrayEnd = strchr(lvalStr, '[');
if (arrayEnd == nullptr)
return; //should this return an error?
size_t arrayNameLen = arrayEnd - lvalStr;
SkString arrayStr(lvalStr, arrayNameLen);
SkASSERT(fTarget); //this return an error?
fFieldInfo = fTarget->getMember(arrayStr.c_str());
SkString scriptStr(arrayEnd + 1, lval.size() - arrayNameLen - 2);
SkAnimatorScript::EvaluateInt(maker, this, scriptStr.c_str(), &fFieldOffset);
}
}
void SkAnimateBase::packARGB(SkScalar array[], int count, SkTDOperandArray* converted)
{
SkASSERT(count == 4);
converted->setCount(1);
SkColor color = SkColorSetARGB(SkScalarRoundToInt(array[0]),
SkScalarRoundToInt(array[1]),
SkScalarRoundToInt(array[2]),
SkScalarRoundToInt(array[3]));
(*converted)[0].fS32 = color;
}
void SkAnimateBase::refresh(SkAnimateMaker& ) {
}
bool SkAnimateBase::setParent(SkDisplayable* apply) {
SkASSERT(apply->isApply());
fApply = (SkApply*) apply;
return false;
}
bool SkAnimateBase::setProperty(int index, SkScriptValue& value) {
bool boolValue = SkToBool(value.fOperand.fS32);
switch (index) {
case SK_PROPERTY(dynamic):
fDynamic = boolValue;
goto checkForBool;
case SK_PROPERTY(values):
fHasValues = true;
SkASSERT(value.fType == SkType_String);
to = *value.fOperand.fString;
break;
case SK_PROPERTY(mirror):
fMirror = boolValue;
goto checkForBool;
case SK_PROPERTY(reset):
fReset = boolValue;
checkForBool:
SkASSERT(value.fType == SkType_Boolean);
break;
default:
return false;
}
return true;
}
void SkAnimateBase::setTarget(SkAnimateMaker& maker) {
if (target.size()) {
SkAnimatorScript engine(maker, this, SkType_Displayable);
const char* script = target.c_str();
SkScriptValue scriptValue;
bool success = engine.evaluateScript(&script, &scriptValue);
if (success && scriptValue.fType == SkType_Displayable)
fTarget = scriptValue.fOperand.fDrawable;
else if (maker.find(target.c_str(), (SkDisplayable**) &fTarget) == false) {
if (fApply->getMode() == SkApply::kMode_create)
return; // may not be an error
if (engine.getError() != SkScriptEngine::kNoError)
maker.setScriptError(engine);
else {
maker.setErrorNoun(target);
maker.setErrorCode(SkDisplayXMLParserError::kTargetIDNotFound);
}
return;
}
if (fApply && fApply->getMode() != SkApply::kMode_create)
target.reset();
}
}
bool SkAnimateBase::targetNeedsInitialization() const {
return false;
}