|  | 
 | /* | 
 |  * 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 "SkMemberInfo.h" | 
 | #include "SkAnimateMaker.h" | 
 | #include "SkAnimatorScript.h" | 
 | #include "SkBase64.h" | 
 | #include "SkCamera.h" | 
 | #include "SkDisplayable.h" | 
 | #include "SkDisplayTypes.h" | 
 | #include "SkDraw3D.h" | 
 | #include "SkDrawColor.h" | 
 | #include "SkParse.h" | 
 | #include "SkScript.h" | 
 | #include "SkTSearch.h" | 
 | #include "SkTypedArray.h" | 
 |  | 
 | size_t SkMemberInfo::GetSize(SkDisplayTypes type) { // size of simple types only | 
 |     size_t byteSize; | 
 |     switch (type) { | 
 |         case SkType_ARGB: | 
 |             byteSize = sizeof(SkColor); | 
 |             break; | 
 |         case SkType_AddMode: | 
 |         case SkType_Align: | 
 |         case SkType_ApplyMode: | 
 |         case SkType_ApplyTransition: | 
 |         case SkType_BitmapEncoding: | 
 |         case SkType_Boolean: | 
 |         case SkType_Cap: | 
 |         case SkType_EventCode: | 
 |         case SkType_EventKind: | 
 |         case SkType_EventMode: | 
 |         case SkType_FilterType: | 
 |         case SkType_FontStyle: | 
 |         case SkType_FromPathMode: | 
 |         case SkType_Join: | 
 |         case SkType_MaskFilterBlurStyle: | 
 |         case SkType_PathDirection: | 
 |         case SkType_Style: | 
 |         case SkType_TileMode: | 
 |         case SkType_Xfermode: | 
 |             byteSize = sizeof(int); | 
 |             break; | 
 |         case SkType_Base64: // assume base64 data is always const, copied by ref | 
 |         case SkType_Displayable: | 
 |         case SkType_Drawable: | 
 |         case SkType_Matrix: | 
 |             byteSize = sizeof(void*);  | 
 |             break; | 
 |         case SkType_MSec: | 
 |             byteSize = sizeof(SkMSec); | 
 |             break; | 
 |         case SkType_Point: | 
 |             byteSize = sizeof(SkPoint); | 
 |             break; | 
 |         case SkType_3D_Point: | 
 |             byteSize = sizeof(Sk3D_Point); | 
 |             break; | 
 |         case SkType_Int: | 
 |             byteSize = sizeof(int32_t); | 
 |             break; | 
 |         case SkType_Float: | 
 |             byteSize = sizeof(SkScalar); | 
 |             break; | 
 |         case SkType_DynamicString: | 
 |         case SkType_String: | 
 |             byteSize = sizeof(SkString);    // assume we'll copy by reference, not value | 
 |             break; | 
 |         default: | 
 | //          SkASSERT(0); | 
 |             byteSize = 0; | 
 |     } | 
 |     return byteSize; | 
 | } | 
 |  | 
 | bool SkMemberInfo::getArrayValue(const SkDisplayable* displayable, int index, SkOperand* value) const { | 
 |     SkASSERT(fType != SkType_String && fType != SkType_MemberProperty); | 
 |     char* valuePtr = (char*) *(SkOperand**) memberData(displayable); | 
 |     SkDisplayTypes type = (SkDisplayTypes) 0; | 
 |     if (displayable->getType() == SkType_Array) { | 
 |         SkDisplayArray* dispArray = (SkDisplayArray*) displayable; | 
 |         if (dispArray->values.count() <= index) | 
 |             return false; | 
 |         type = dispArray->values.getType(); | 
 |     } else { | 
 |         SkASSERT(0); // incomplete | 
 |     } | 
 |     size_t byteSize = GetSize(type); | 
 |     memcpy(value, valuePtr + index * byteSize, byteSize); | 
 |     return true; | 
 | } | 
 |  | 
 | size_t SkMemberInfo::getSize(const SkDisplayable* displayable) const { | 
 |     size_t byteSize; | 
 |     switch (fType) { | 
 |         case SkType_MemberProperty: | 
 |             byteSize = GetSize(propertyType()); | 
 |             break; | 
 |         case SkType_Array: { | 
 |             SkDisplayTypes type; | 
 |             if (displayable == NULL) | 
 |                 return sizeof(int); | 
 |             if (displayable->getType() == SkType_Array) { | 
 |                 SkDisplayArray* dispArray = (SkDisplayArray*) displayable; | 
 |                 type = dispArray->values.getType(); | 
 |             } else | 
 |                 type = propertyType(); | 
 |             SkTDOperandArray* array = (SkTDOperandArray*) memberData(displayable); | 
 |             byteSize = GetSize(type) * array->count(); | 
 |             } break; | 
 |         default: | 
 |             byteSize = GetSize((SkDisplayTypes) fType); | 
 |     } | 
 |     return byteSize; | 
 | } | 
 |  | 
 | void SkMemberInfo::getString(const SkDisplayable* displayable, SkString** string) const { | 
 |     if (fType == SkType_MemberProperty) { | 
 |         SkScriptValue value; | 
 |         displayable->getProperty(propertyIndex(), &value); | 
 |         SkASSERT(value.fType == SkType_String); | 
 |         *string = value.fOperand.fString; | 
 |         return; | 
 |     } | 
 |     SkASSERT(fCount == sizeof(SkString) / sizeof(SkScalar)); | 
 |     SkASSERT(fType == SkType_String || fType == SkType_DynamicString); | 
 |     void* valuePtr = memberData(displayable); | 
 |     *string = (SkString*) valuePtr; | 
 | } | 
 |  | 
 | void SkMemberInfo::getValue(const SkDisplayable* displayable, SkOperand value[], int count) const { | 
 |     SkASSERT(fType != SkType_String && fType != SkType_MemberProperty); | 
 |     SkASSERT(count == fCount);   | 
 |     void* valuePtr = memberData(displayable); | 
 |     size_t byteSize = getSize(displayable); | 
 |     SkASSERT(sizeof(value[0].fScalar) == sizeof(value[0])); // no support for 64 bit pointers, yet | 
 |     memcpy(value, valuePtr, byteSize); | 
 | } | 
 |  | 
 | void SkMemberInfo::setString(SkDisplayable* displayable, SkString* value) const { | 
 |     SkString* string = (SkString*) memberData(displayable); | 
 |     string->set(*value); | 
 |     displayable->dirty(); | 
 | } | 
 |  | 
 | void SkMemberInfo::setValue(SkDisplayable* displayable, const SkOperand values[],  | 
 |                             int count) const { | 
 |     SkASSERT(sizeof(values[0].fScalar) == sizeof(values[0]));   // no support for 64 bit pointers, yet | 
 |     char* dst = (char*) memberData(displayable); | 
 |     if (fType == SkType_Array) { | 
 |         SkTDScalarArray* array = (SkTDScalarArray* ) dst; | 
 |         array->setCount(count); | 
 |         dst = (char*) array->begin(); | 
 |     } | 
 |     memcpy(dst, values, count * sizeof(SkOperand)); | 
 |     displayable->dirty(); | 
 | } | 
 |  | 
 |                              | 
 | static inline bool is_between(int c, int min, int max) | 
 | { | 
 |     return (unsigned)(c - min) <= (unsigned)(max - min); | 
 | } | 
 |  | 
 | static inline bool is_hex(int c) | 
 | { | 
 |     if (is_between(c, '0', '9')) | 
 |         return true; | 
 |     c |= 0x20;  // make us lower-case | 
 |     if (is_between(c, 'a', 'f')) | 
 |         return true; | 
 |     return false; | 
 | } | 
 |  | 
 |  | 
 | bool SkMemberInfo::setValue(SkAnimateMaker& maker, SkTDOperandArray* arrayStorage,  | 
 |     int storageOffset, int maxStorage, SkDisplayable* displayable, SkDisplayTypes outType, | 
 |     const char rawValue[], size_t rawValueLen) const  | 
 | { | 
 |     SkString valueStr(rawValue, rawValueLen); | 
 |     SkScriptValue scriptValue; | 
 |     scriptValue.fType = SkType_Unknown; | 
 |     scriptValue.fOperand.fS32 = 0; | 
 |     SkDisplayTypes type = getType(); | 
 |     SkAnimatorScript engine(maker, displayable, type); | 
 |     if (arrayStorage) | 
 |         displayable = NULL; | 
 |     bool success = true; | 
 |     void* untypedStorage = NULL; | 
 |     if (displayable && fType != SkType_MemberProperty && fType != SkType_MemberFunction) | 
 |         untypedStorage = (SkTDOperandArray*) memberData(displayable); | 
 |  | 
 |     if (type == SkType_ARGB) { | 
 |         // for both SpiderMonkey and SkiaScript, substitute any #xyz or #xxyyzz first | 
 |             // it's enough to expand the colors into 0xFFxxyyzz | 
 |         const char* poundPos; | 
 |         while ((poundPos = strchr(valueStr.c_str(), '#')) != NULL) { | 
 |             size_t offset = poundPos - valueStr.c_str(); | 
 |             if (valueStr.size() - offset < 4) | 
 |                 break; | 
 |             char r = poundPos[1]; | 
 |             char g = poundPos[2]; | 
 |             char b = poundPos[3]; | 
 |             if (is_hex(r) == false || is_hex(g) == false || is_hex(b) == false) | 
 |                 break; | 
 |             char hex = poundPos[4]; | 
 |             if (is_hex(hex) == false) { | 
 |                 valueStr.insertUnichar(offset + 1, r); | 
 |                 valueStr.insertUnichar(offset + 3, g); | 
 |                 valueStr.insertUnichar(offset + 5, b); | 
 |             } | 
 |             *(char*) poundPos = '0'; // overwrite '#' | 
 |             valueStr.insert(offset + 1, "xFF"); | 
 |         }  | 
 |     } | 
 |     if (SkDisplayType::IsDisplayable(&maker, type) || SkDisplayType::IsEnum(&maker, type) || type == SkType_ARGB) | 
 |         goto scriptCommon; | 
 |     switch (type) { | 
 |         case SkType_String: | 
 | #if 0 | 
 |             if (displayable && displayable->isAnimate()) { | 
 |                  | 
 |                 goto noScriptString; | 
 |             }  | 
 |             if (strncmp(rawValue, "#string:", sizeof("#string:") - 1) == 0) { | 
 |                 SkASSERT(sizeof("string") == sizeof("script")); | 
 |                 char* stringHeader = valueStr.writable_str(); | 
 |                 memcpy(&stringHeader[1], "script", sizeof("script") - 1); | 
 |                 rawValue = valueStr.c_str(); | 
 |                 goto noScriptString; | 
 |             } else  | 
 | #endif | 
 |             if (strncmp(rawValue, "#script:", sizeof("#script:") - 1) != 0) | 
 |                 goto noScriptString; | 
 |             valueStr.remove(0, 8); | 
 |         case SkType_Unknown: | 
 |         case SkType_Int:  | 
 |         case SkType_MSec:  // for the purposes of script, MSec is treated as a Scalar | 
 |         case SkType_Point: | 
 |         case SkType_3D_Point: | 
 |         case SkType_Float: | 
 |         case SkType_Array: | 
 | scriptCommon: { | 
 |                 const char* script = valueStr.c_str(); | 
 |                 success = engine.evaluateScript(&script, &scriptValue); | 
 |                 if (success == false) { | 
 |                     maker.setScriptError(engine); | 
 |                     return false; | 
 |                 } | 
 |             } | 
 |             SkASSERT(success); | 
 |             if (scriptValue.fType == SkType_Displayable) { | 
 |                 if (type == SkType_String) { | 
 |                     const char* charPtr = NULL; | 
 |                     maker.findKey(scriptValue.fOperand.fDisplayable, &charPtr); | 
 |                     scriptValue.fOperand.fString = new SkString(charPtr); | 
 |                     scriptValue.fType = SkType_String; | 
 |                     engine.SkScriptEngine::track(scriptValue.fOperand.fString); | 
 |                     break; | 
 |                 } | 
 |                 SkASSERT(SkDisplayType::IsDisplayable(&maker, type)); | 
 |                 if (displayable) | 
 |                     displayable->setReference(this, scriptValue.fOperand.fDisplayable); | 
 |                 else | 
 |                     arrayStorage->begin()[0].fDisplayable = scriptValue.fOperand.fDisplayable; | 
 |                 return true; | 
 |             } | 
 |             if (type != scriptValue.fType) { | 
 |                 if (scriptValue.fType == SkType_Array) { | 
 |                     engine.forget(scriptValue.getArray()); | 
 |                     goto writeStruct; // real structs have already been written by script | 
 |                 } | 
 |                 switch (type) { | 
 |                     case SkType_String: | 
 |                         success = engine.convertTo(SkType_String, &scriptValue); | 
 |                         break; | 
 |                     case SkType_MSec: | 
 |                     case SkType_Float: | 
 |                         success = engine.convertTo(SkType_Float, &scriptValue); | 
 |                         break; | 
 |                     case SkType_Int: | 
 |                         success = engine.convertTo(SkType_Int, &scriptValue); | 
 |                         break; | 
 |                     case SkType_Array: | 
 |                         success = engine.convertTo(arrayType(), &scriptValue); | 
 |                         // !!! incomplete; create array of appropriate type and add scriptValue to it | 
 |                         SkASSERT(0); | 
 |                         break; | 
 |                     case SkType_Displayable: | 
 |                     case SkType_Drawable: | 
 |                         return false;   // no way to convert other types to this | 
 |                     default:    // to avoid warnings | 
 |                         break; | 
 |                 } | 
 |                 if (success == false) | 
 |                     return false; | 
 |             } | 
 |             if (type == SkType_MSec) | 
 |                 scriptValue.fOperand.fMSec = SkScalarMulRound(scriptValue.fOperand.fScalar, 1000); | 
 |             scriptValue.fType = type; | 
 |         break; | 
 |         noScriptString: | 
 |         case SkType_DynamicString: | 
 |             if (fType == SkType_MemberProperty && displayable) { | 
 |                 SkString string(rawValue, rawValueLen); | 
 |                 SkScriptValue scriptValue; | 
 |                 scriptValue.fOperand.fString = &string; | 
 |                 scriptValue.fType = SkType_String; | 
 |                 displayable->setProperty(propertyIndex(), scriptValue); | 
 |             } else if (displayable) { | 
 |                 SkString* string = (SkString*) memberData(displayable); | 
 |                 string->set(rawValue, rawValueLen); | 
 |             } else { | 
 |                 SkASSERT(arrayStorage->count() == 1); | 
 |                 arrayStorage->begin()->fString->set(rawValue, rawValueLen); | 
 |             } | 
 |             goto dirty; | 
 |         case SkType_Base64: { | 
 |             SkBase64 base64; | 
 |             base64.decode(rawValue, rawValueLen); | 
 |             *(SkBase64* ) untypedStorage = base64; | 
 |             } goto dirty; | 
 |         default: | 
 |             SkASSERT(0); | 
 |             break; | 
 |     } | 
 | //  if (SkDisplayType::IsStruct(type) == false)  | 
 |     { | 
 | writeStruct: | 
 |         if (writeValue(displayable, arrayStorage, storageOffset, maxStorage,  | 
 |                 untypedStorage, outType, scriptValue)) { | 
 |                     maker.setErrorCode(SkDisplayXMLParserError::kUnexpectedType); | 
 |             return false; | 
 |         } | 
 |     } | 
 | dirty: | 
 |     if (displayable) | 
 |         displayable->dirty(); | 
 |     return true; | 
 | } | 
 |  | 
 | bool SkMemberInfo::setValue(SkAnimateMaker& maker, SkTDOperandArray* arrayStorage,  | 
 |         int storageOffset, int maxStorage, SkDisplayable* displayable, SkDisplayTypes outType, | 
 |         SkString& raw) const { | 
 |     return setValue(maker, arrayStorage, storageOffset, maxStorage, displayable, outType, raw.c_str(), | 
 |         raw.size()); | 
 | } | 
 |  | 
 | bool SkMemberInfo::writeValue(SkDisplayable* displayable, SkTDOperandArray* arrayStorage,  | 
 |     int storageOffset, int maxStorage, void* untypedStorage, SkDisplayTypes outType,  | 
 |     SkScriptValue& scriptValue) const | 
 | { | 
 |     SkOperand* storage = untypedStorage ? (SkOperand*) untypedStorage : arrayStorage ?  | 
 |         arrayStorage->begin() : NULL; | 
 |     if (storage) | 
 |         storage += storageOffset; | 
 |     SkDisplayTypes type = getType(); | 
 |     if (fType == SkType_MemberProperty) { | 
 |         if(displayable) | 
 |             displayable->setProperty(propertyIndex(), scriptValue); | 
 |         else { | 
 |             SkASSERT(storageOffset < arrayStorage->count()); | 
 |             switch (scriptValue.fType) { | 
 |                 case SkType_Boolean: | 
 |                 case SkType_Float: | 
 |                 case SkType_Int: | 
 |                     memcpy(&storage->fScalar, &scriptValue.fOperand.fScalar, sizeof(SkScalar)); | 
 |                     break; | 
 |                 case SkType_Array: | 
 |                     memcpy(&storage->fScalar, scriptValue.fOperand.fArray->begin(), scriptValue.fOperand.fArray->count() * sizeof(SkScalar)); | 
 |                     break; | 
 |                 case SkType_String: | 
 |                     storage->fString->set(*scriptValue.fOperand.fString); | 
 |                     break; | 
 |                 default: | 
 |                     SkASSERT(0);    // type isn't handled yet | 
 |             } | 
 |         } | 
 |     } else if (fType == SkType_MemberFunction) { | 
 |         SkASSERT(scriptValue.fType == SkType_Array); | 
 |         if (displayable) | 
 |             displayable->executeFunction(displayable, this, scriptValue.fOperand.fArray, NULL); | 
 |         else { | 
 |             int count = scriptValue.fOperand.fArray->count(); | 
 |     //      SkASSERT(maxStorage == 0 || count == maxStorage); | 
 |             if (arrayStorage->count() == 2) | 
 |                 arrayStorage->setCount(2 * count); | 
 |             else { | 
 |                 storageOffset *= count; | 
 |                 SkASSERT(count + storageOffset <= arrayStorage->count()); | 
 |             } | 
 |             memcpy(&(*arrayStorage)[storageOffset], scriptValue.fOperand.fArray->begin(), count * sizeof(SkOperand)); | 
 |         } | 
 |  | 
 |     } else if (fType == SkType_Array) { | 
 |         SkTypedArray* destArray = (SkTypedArray*) (untypedStorage ? untypedStorage : arrayStorage); | 
 |         SkASSERT(destArray); | 
 |     //  destArray->setCount(0); | 
 |         if (scriptValue.fType != SkType_Array) { | 
 |             SkASSERT(type == scriptValue.fType); | 
 |     //      SkASSERT(storageOffset + 1 <= maxStorage); | 
 |             destArray->setCount(storageOffset + 1); | 
 |             (*destArray)[storageOffset] = scriptValue.fOperand; | 
 |         } else { | 
 |             if (type == SkType_Unknown) { | 
 |                 type = scriptValue.fOperand.fArray->getType(); | 
 |                 destArray->setType(type); | 
 |             } | 
 |             SkASSERT(type == scriptValue.fOperand.fArray->getType()); | 
 |             int count = scriptValue.fOperand.fArray->count(); | 
 |     //      SkASSERT(storageOffset + count <= maxStorage); | 
 |             destArray->setCount(storageOffset + count); | 
 |             memcpy(destArray->begin() + storageOffset, scriptValue.fOperand.fArray->begin(), sizeof(SkOperand) * count); | 
 |         } | 
 |     } else if (type == SkType_String) { | 
 |         SkString* string = untypedStorage ? (SkString*) untypedStorage : (*arrayStorage)[storageOffset].fString; | 
 |         string->set(*scriptValue.fOperand.fString); | 
 |     } else if (type == SkType_ARGB && outType == SkType_Float) { | 
 |         SkTypedArray* array = scriptValue.fOperand.fArray; | 
 |         SkASSERT(scriptValue.fType == SkType_Int || scriptValue.fType == SkType_ARGB ||  | 
 |             scriptValue.fType == SkType_Array); | 
 |         SkASSERT(scriptValue.fType != SkType_Array || (array != NULL && | 
 |             array->getType() == SkType_Int)); | 
 |         int numberOfColors = scriptValue.fType == SkType_Array ? array->count() : 1; | 
 |         int numberOfComponents = numberOfColors * 4; | 
 |     //  SkASSERT(maxStorage == 0 || maxStorage == numberOfComponents); | 
 |         if (maxStorage == 0) | 
 |             arrayStorage->setCount(numberOfComponents); | 
 |         for (int index = 0; index < numberOfColors; index++) { | 
 |             SkColor color = scriptValue.fType == SkType_Array ?  | 
 |                 (SkColor) array->begin()[index].fS32 : (SkColor) scriptValue.fOperand.fS32; | 
 |             storage[0].fScalar = SkIntToScalar(SkColorGetA(color)); | 
 |             storage[1].fScalar = SkIntToScalar(SkColorGetR(color)); | 
 |             storage[2].fScalar = SkIntToScalar(SkColorGetG(color)); | 
 |             storage[3].fScalar = SkIntToScalar(SkColorGetB(color)); | 
 |             storage += 4; | 
 |         } | 
 |     } else if (SkDisplayType::IsStruct(NULL /* !!! maker*/, type)) { | 
 |         if (scriptValue.fType != SkType_Array) | 
 |             return true;    // error | 
 |         SkASSERT(sizeof(SkScalar) == sizeof(SkOperand)); // !!! no 64 bit pointer support yet | 
 |         int count = scriptValue.fOperand.fArray->count(); | 
 |         if (count > 0) { | 
 |             SkASSERT(fCount == count); | 
 |             memcpy(storage, scriptValue.fOperand.fArray->begin(), count * sizeof(SkOperand)); | 
 |         } | 
 |     } else if (scriptValue.fType == SkType_Array) { | 
 |         SkASSERT(scriptValue.fOperand.fArray->getType() == type); | 
 |         SkASSERT(scriptValue.fOperand.fArray->count() == getCount()); | 
 |         memcpy(storage, scriptValue.fOperand.fArray->begin(), getCount() * sizeof(SkOperand)); | 
 |     } else { | 
 |         memcpy(storage, &scriptValue.fOperand, sizeof(SkOperand)); | 
 |     } | 
 |     return false; | 
 | } | 
 |  | 
 |  | 
 | //void SkMemberInfo::setValue(SkDisplayable* displayable, const char value[], const char name[]) const { | 
 | //  void* valuePtr = (void*) ((char*) displayable + fOffset); | 
 | //  switch (fType) { | 
 | //      case SkType_Point3D: { | 
 | //          static const char xyz[] = "x|y|z"; | 
 | //          int index = find_one(xyz, name); | 
 | //          SkASSERT(index >= 0); | 
 | //          valuePtr = (void*) ((char*) valuePtr + index * sizeof(SkScalar)); | 
 | //          } break; | 
 | //      default: | 
 | //          SkASSERT(0); | 
 | //  } | 
 | //  SkParse::FindScalar(value, (SkScalar*) valuePtr); | 
 | //  displayable->dirty(); | 
 | //} | 
 |  | 
 | #if SK_USE_CONDENSED_INFO == 0 | 
 |  | 
 | // Find Nth memberInfo | 
 | const SkMemberInfo* SkMemberInfo::Find(const SkMemberInfo info[], int count, int* index) { | 
 |     SkASSERT(*index >= 0); | 
 |     if (info->fType == SkType_BaseClassInfo) { | 
 |         const SkMemberInfo* inherited = (SkMemberInfo*) info->fName; | 
 |         const SkMemberInfo* result = SkMemberInfo::Find(inherited, info->fCount, index); | 
 |         if (result != NULL) | 
 |             return result; | 
 |         if (--count == 0) | 
 |             return NULL; | 
 |         info++; | 
 |     } | 
 |     SkASSERT(info->fName); | 
 |     SkASSERT(info->fType != SkType_BaseClassInfo); | 
 |     if (*index >= count) { | 
 |         *index -= count; | 
 |         return NULL; | 
 |     } | 
 |     return &info[*index]; | 
 | } | 
 |  | 
 | // Find named memberinfo | 
 | const SkMemberInfo* SkMemberInfo::Find(const SkMemberInfo info[], int count, const char** matchPtr) { | 
 |     const char* match = *matchPtr; | 
 |     if (info->fType == SkType_BaseClassInfo) { | 
 |         const SkMemberInfo* inherited = (SkMemberInfo*) info->fName; | 
 |         const SkMemberInfo* result = SkMemberInfo::Find(inherited, info->fCount, matchPtr); | 
 |         if (result != NULL) | 
 |             return result; | 
 |         if (--count == 0) | 
 |             return NULL; | 
 |         info++; | 
 |     } | 
 |     SkASSERT(info->fName); | 
 |     SkASSERT(info->fType != SkType_BaseClassInfo); | 
 |     int index = SkStrSearch(&info->fName, count, match, sizeof(*info)); | 
 |     if (index < 0 || index >= count) | 
 |         return NULL; | 
 |     return &info[index]; | 
 | } | 
 |  | 
 | const SkMemberInfo* SkMemberInfo::getInherited() const { | 
 |     return (SkMemberInfo*) fName; | 
 | } | 
 |  | 
 | #endif // SK_USE_CONDENSED_INFO == 0 | 
 |  | 
 | #if 0 | 
 | bool SkMemberInfo::SetValue(void* valuePtr, const char value[], SkDisplayTypes type,  | 
 |                             int count) { | 
 |     switch (type) { | 
 |         case SkType_Animate: | 
 |         case SkType_BaseBitmap:  | 
 |         case SkType_Bitmap: | 
 |         case SkType_Dash: | 
 |         case SkType_Displayable: | 
 |         case SkType_Drawable: | 
 |         case SkType_Matrix: | 
 |         case SkType_Path: | 
 |         case SkType_Text: | 
 |         case SkType_3D_Patch: | 
 |             return false; // ref to object; caller must resolve | 
 |         case SkType_MSec: { | 
 |             SkParse::FindMSec(value, (SkMSec*) valuePtr); | 
 |             } break; | 
 |         case SkType_3D_Point: | 
 |         case SkType_Point: | 
 |     //  case SkType_PointArray: | 
 |         case SkType_ScalarArray:  | 
 |             SkParse::FindScalars(value, (SkScalar*) valuePtr, count); | 
 |             break; | 
 |         default: | 
 |             SkASSERT(0); | 
 |     } | 
 |     return true; | 
 | } | 
 | #endif | 
 |  | 
 |  |