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