/* libs/graphics/animator/SkDisplayable.cpp ** ** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include "SkDisplayable.h" #include "SkDisplayApply.h" #include "SkParse.h" #ifdef SK_DEBUG #include "SkDisplayList.h" #endif #include "SkDisplayTypes.h" #ifdef SK_FIND_LEAKS // int SkDisplayable::fAllocationCount; SkTDDisplayableArray SkDisplayable::fAllocations; #endif #ifdef SK_DEBUG SkDisplayable::SkDisplayable() { id = _id.c_str(); #ifdef SK_FIND_LEAKS // fAllocationCount++; *fAllocations.append() = this; #endif } #endif SkDisplayable::~SkDisplayable() { #ifdef SK_FIND_LEAKS // fAllocationCount--; int index = fAllocations.find(this); SkASSERT(index >= 0); fAllocations.remove(index); #endif } bool SkDisplayable::add(SkAnimateMaker& , SkDisplayable* child) { return false; } //void SkDisplayable::apply(SkAnimateMaker& , const SkMemberInfo* , // SkDisplayable* , SkScalar [], int count) { // SkASSERT(0); //} bool SkDisplayable::canContainDependents() const { return false; } bool SkDisplayable::childrenNeedDisposing() const { return false; } void SkDisplayable::clearBounder() { } bool SkDisplayable::contains(SkDisplayable* ) { return false; } SkDisplayable* SkDisplayable::contains(const SkString& ) { return NULL; } SkDisplayable* SkDisplayable::deepCopy(SkAnimateMaker* maker) { SkDisplayTypes type = getType(); if (type == SkType_Unknown) { SkASSERT(0); return NULL; } SkDisplayable* copy = SkDisplayType::CreateInstance(maker, type); int index = -1; int propIndex = 0; const SkMemberInfo* info; do { info = copy->getMember(++index); if (info == NULL) break; if (info->fType == SkType_MemberProperty) { SkScriptValue value; if (getProperty(propIndex, &value)) copy->setProperty(propIndex, value); propIndex++; continue; } if (info->fType == SkType_MemberFunction) continue; if (info->fType == SkType_Array) { SkTDOperandArray* array = (SkTDOperandArray*) info->memberData(this); int arrayCount; if (array == NULL || (arrayCount = array->count()) == 0) continue; SkTDOperandArray* copyArray = (SkTDOperandArray*) info->memberData(copy); copyArray->setCount(arrayCount); SkDisplayTypes elementType; if (type == SkType_Array) { SkDisplayArray* dispArray = (SkDisplayArray*) this; elementType = dispArray->values.getType(); } else elementType = info->arrayType(); size_t elementSize = SkMemberInfo::GetSize(elementType); size_t byteSize = elementSize * arrayCount; memcpy(copyArray->begin(), array->begin(), byteSize); continue; } if (SkDisplayType::IsDisplayable(maker, info->fType)) { SkDisplayable** displayable = (SkDisplayable**) info->memberData(this); if (*displayable == NULL || *displayable == (SkDisplayable*) -1) continue; SkDisplayable* deeper = (*displayable)->deepCopy(maker); info->setMemberData(copy, deeper, sizeof(deeper)); continue; } if (info->fType == SkType_String || info->fType == SkType_DynamicString) { SkString* string; info->getString(this, &string); info->setString(copy, string); continue; } void* data = info->memberData(this); size_t size = SkMemberInfo::GetSize(info->fType); info->setMemberData(copy, data, size); } while (true); copy->dirty(); return copy; } void SkDisplayable::dirty() { } #ifdef SK_DUMP_ENABLED void SkDisplayable::dump(SkAnimateMaker* maker) { dumpBase(maker); #if SK_USE_CONDENSED_INFO == 0 this->dumpAttrs(maker); this->dumpChildren(maker); #endif } void SkDisplayable::dumpAttrs(SkAnimateMaker* maker) { SkDisplayTypes type = getType(); if (type == SkType_Unknown) { //SkDebugf("/>\n"); return; } SkDisplayable* blankCopy = SkDisplayType::CreateInstance(maker, type); int index = -1; int propIndex = 0; const SkMemberInfo* info; const SkMemberInfo* blankInfo; SkScriptValue value; SkScriptValue blankValue; SkOperand values[2]; SkOperand blankValues[2]; do { info = this->getMember(++index); if (NULL == info) { //SkDebugf("\n"); break; } if (SkType_MemberProperty == info->fType) { if (getProperty(propIndex, &value)) { blankCopy->getProperty(propIndex, &blankValue); //last two are dummies dumpValues(info, value.fType, value.fOperand, blankValue.fOperand, value.fOperand, blankValue.fOperand); } propIndex++; continue; } if (SkDisplayType::IsDisplayable(maker, info->fType)) { continue; } if (info->fType == SkType_MemberFunction) continue; if (info->fType == SkType_Array) { SkTDOperandArray* array = (SkTDOperandArray*) info->memberData(this); int arrayCount; if (array == NULL || (arrayCount = array->count()) == 0) continue; SkDisplayTypes elementType; if (type == SkType_Array) { SkDisplayArray* dispArray = (SkDisplayArray*) this; elementType = dispArray->values.getType(); } else elementType = info->arrayType(); bool firstElem = true; SkDebugf("%s=\"[", info->fName); for (SkOperand* op = array->begin(); op < array->end(); op++) { if (!firstElem) SkDebugf(","); switch (elementType) { case SkType_Displayable: SkDebugf("%s", op->fDisplayable->id); break; case SkType_Int: SkDebugf("%d", op->fS32); break; case SkType_Float: #ifdef SK_CAN_USE_FLOAT SkDebugf("%g", SkScalarToFloat(op->fScalar)); #else SkDebugf("%x", op->fScalar); #endif break; case SkType_String: case SkType_DynamicString: SkDebugf("%s", op->fString->c_str()); break; default: break; } firstElem = false; } SkDebugf("]\" "); continue; } if (info->fType == SkType_String || info->fType == SkType_DynamicString) { SkString* string; info->getString(this, &string); if (string->isEmpty() == false) SkDebugf("%s=\"%s\"\t", info->fName, string->c_str()); continue; } blankInfo = blankCopy->getMember(index); int i = info->fCount; info->getValue(this, values, i); blankInfo->getValue(blankCopy, blankValues, i); dumpValues(info, info->fType, values[0], blankValues[0], values[1], blankValues[1]); } while (true); delete blankCopy; } void SkDisplayable::dumpBase(SkAnimateMaker* maker) { SkDisplayTypes type = getType(); const char* elementName = "(unknown)"; if (type != SkType_Unknown && type != SkType_Screenplay) elementName = SkDisplayType::GetName(maker, type); SkDebugf("%*s", SkDisplayList::fIndent, ""); if (SkDisplayList::fDumpIndex != 0 && SkDisplayList::fIndent == 0) SkDebugf("%d: ", SkDisplayList::fDumpIndex); SkDebugf("<%s ", elementName); if (strcmp(id,"") != 0) SkDebugf("id=\"%s\" ", id); } void SkDisplayable::dumpChildren(SkAnimateMaker* maker, bool closedAngle) { int index = -1; const SkMemberInfo* info; index = -1; SkDisplayList::fIndent += 4; do { info = this->getMember(++index); if (NULL == info) { break; } if (SkDisplayType::IsDisplayable(maker, info->fType)) { SkDisplayable** displayable = (SkDisplayable**) info->memberData(this); if (*displayable == NULL || *displayable == (SkDisplayable*) -1) continue; if (closedAngle == false) { SkDebugf(">\n"); closedAngle = true; } (*displayable)->dump(maker); } } while (true); SkDisplayList::fIndent -= 4; if (closedAngle) dumpEnd(maker); else SkDebugf("/>\n"); } void SkDisplayable::dumpEnd(SkAnimateMaker* maker) { SkDisplayTypes type = getType(); const char* elementName = "(unknown)"; if (type != SkType_Unknown && type != SkType_Screenplay) elementName = SkDisplayType::GetName(maker, type); SkDebugf("%*s", SkDisplayList::fIndent, ""); SkDebugf("</%s>\n", elementName); } void SkDisplayable::dumpEvents() { } void SkDisplayable::dumpValues(const SkMemberInfo* info, SkDisplayTypes type, SkOperand op, SkOperand blankOp, SkOperand op2, SkOperand blankOp2) { switch (type) { case SkType_BitmapEncoding: switch (op.fS32) { case 0 : SkDebugf("type=\"jpeg\" "); break; case 1 : SkDebugf("type=\"png\" "); break; default: SkDebugf("type=\"UNDEFINED\" "); } break; //should make this a separate case in dump attrs, rather than make dump values have a larger signature case SkType_Point: if (op.fScalar != blankOp.fScalar || op2.fScalar != blankOp.fScalar) { #ifdef SK_CAN_USE_FLOAT SkDebugf("%s=\"[%g,%g]\" ", info->fName, SkScalarToFloat(op.fScalar), SkScalarToFloat(op2.fScalar)); #else SkDebugf("%s=\"[%x,%x]\" ", info->fName, op.fScalar, op2.fScalar); #endif } break; case SkType_FromPathMode: switch (op.fS32) { case 0: //don't want to print anything for 0, just adding it to remove it from default: break; case 1: SkDebugf("%s=\"%s\" ", info->fName, "angle"); break; case 2: SkDebugf("%s=\"%s\" ", info->fName, "position"); break; default: SkDebugf("%s=\"INVALID\" ", info->fName); } break; case SkType_MaskFilterBlurStyle: switch (op.fS32) { case 0: break; case 1: SkDebugf("%s=\"%s\" ", info->fName, "solid"); break; case 2: SkDebugf("%s=\"%s\" ", info->fName, "outer"); break; case 3: SkDebugf("%s=\"%s\" ", info->fName, "inner"); break; default: SkDebugf("%s=\"INVALID\" ", info->fName); } break; case SkType_FilterType: if (op.fS32 == 1) SkDebugf("%s=\"%s\" ", info->fName, "bilinear"); break; case SkType_PathDirection: SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "cw" : "ccw"); break; case SkType_FillType: SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "winding" : "evenOdd"); break; case SkType_TileMode: //correct to look at the S32? if (op.fS32 != blankOp.fS32) SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "clamp" : op.fS32 == 1 ? "repeat" : "mirror"); break; case SkType_Boolean: if (op.fS32 != blankOp.fS32) SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "false" : "true"); break; case SkType_Int: if (op.fS32 != blankOp.fS32) SkDebugf(" %s=\"%d\" ", info->fName, op.fS32); break; case SkType_Float: if (op.fScalar != blankOp.fScalar) { //or /65536? #ifdef SK_CAN_USE_FLOAT SkDebugf("%s=\"%g\" ", info->fName, SkScalarToFloat(op.fScalar)); #else SkDebugf("%s=\"%x\" ", info->fName, op.fScalar); #endif } break; case SkType_String: case SkType_DynamicString: if (op.fString->size() > 0) SkDebugf("%s=\"%s\" ", info->fName, op.fString->c_str()); break; case SkType_MSec: if (op.fS32 != blankOp.fS32) { #ifdef SK_CAN_USE_FLOAT SkDebugf(" %s=\"%g\" ", info->fName, SkScalarToFloat(SkScalarDiv(op.fS32, 1000))); #else SkDebugf(" %s=\"%x\" ", info->fName, SkScalarDiv(op.fS32, 1000)); #endif } default: SkDebugf(""); } } #endif bool SkDisplayable::enable( SkAnimateMaker& ) { return false; } void SkDisplayable::enableBounder() { } void SkDisplayable::executeFunction(SkDisplayable* , int index, SkTDArray<SkScriptValue>& , SkDisplayTypes, SkScriptValue* ) { SkASSERT(0); } void SkDisplayable::executeFunction(SkDisplayable* target, const SkMemberInfo* info, SkTypedArray* values, SkScriptValue* value) { SkTDArray<SkScriptValue> typedValues; for (SkOperand* op = values->begin(); op < values->end(); op++) { SkScriptValue temp; temp.fType = values->getType(); temp.fOperand = *op; *typedValues.append() = temp; } executeFunction(target, info->functionIndex(), typedValues, info->getType(), value); } void SkDisplayable::executeFunction2(SkDisplayable* , int index, SkOpArray* params, SkDisplayTypes, SkOperand2* ) { SkASSERT(0); } void SkDisplayable::getBounds(SkRect* rect) { SkASSERT(rect); rect->fLeft = rect->fTop = SK_ScalarMax; rect->fRight= rect->fBottom = -SK_ScalarMax; } const SkFunctionParamType* SkDisplayable::getFunctionsParameters() { return NULL; } const SkMemberInfo* SkDisplayable::getMember(int index) { return NULL; } const SkMemberInfo* SkDisplayable::getMember(const char name[]) { return NULL; } const SkFunctionParamType* SkDisplayable::getParameters(const SkMemberInfo* info, int* paramCount) { const SkFunctionParamType* params = getFunctionsParameters(); SkASSERT(params != NULL); int funcIndex = info->functionIndex(); // !!! eventually break traversing params into an external function (maybe this whole function) int index = funcIndex; int offset = 0; while (--index >= 0) { while (params[offset] != 0) offset++; offset++; } int count = 0; while (params[offset] != 0) { count++; offset++; } *paramCount = count; return ¶ms[offset - count]; } SkDisplayable* SkDisplayable::getParent() const { return NULL; } bool SkDisplayable::getProperty(int index, SkScriptValue* ) const { // SkASSERT(0); return false; } bool SkDisplayable::getProperty2(int index, SkOperand2* value) const { SkASSERT(0); return false; } SkDisplayTypes SkDisplayable::getType() const { return SkType_Unknown; } bool SkDisplayable::hasEnable() const { return false; } bool SkDisplayable::isDrawable() const { return false; } void SkDisplayable::onEndElement(SkAnimateMaker& ) {} const SkMemberInfo* SkDisplayable::preferredChild(SkDisplayTypes type) { return NULL; } bool SkDisplayable::resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply) { return false; } //SkDisplayable* SkDisplayable::resolveTarget(SkAnimateMaker& ) { // return this; //} void SkDisplayable::setChildHasID() { } bool SkDisplayable::setParent(SkDisplayable* ) { return false; } bool SkDisplayable::setProperty(int index, SkScriptValue& ) { //SkASSERT(0); return false; } void SkDisplayable::setReference(const SkMemberInfo* info, SkDisplayable* displayable) { if (info->fType == SkType_MemberProperty) { SkScriptValue scriptValue; scriptValue.fOperand.fDisplayable = displayable; scriptValue.fType = displayable->getType(); setProperty(info->propertyIndex(), scriptValue); } else if (info->fType == SkType_Array) { SkASSERT(displayable->getType() == SkType_Array); SkDisplayArray* dispArray = (SkDisplayArray*) displayable; SkTDScalarArray* array = (SkTDScalarArray* ) info->memberData(this); array->setCount(dispArray->values.count()); memcpy(array->begin(), dispArray->values.begin(), dispArray->values.count() * sizeof(int)); // // !!! need a way for interpreter engine to own array // !!! probably need to replace all scriptable arrays with single bigger array // that has operand and type on every element -- or // when array is dirtied, need to get parent to reparse to local array } else { void* storage = info->memberData(this); memcpy(storage, &displayable, sizeof(SkDisplayable*)); } // !!! unclear why displayable is dirtied here // if this is called, this breaks fromPath.xml // displayable->dirty(); } #ifdef SK_DEBUG void SkDisplayable::validate() { } #endif