bool AssetManagerGlue::retrieveAttributes(XmlParser& xmlParser, const NativeArray<int>& attrs, NativeArray<int>* outValues, NativeArray<int>* outIndices) { const ResTable& res(getResources()); ResTable_config config; Res_value value; const size_t NI = attrs.length(); const size_t NV = outValues->length(); SkASSERT(NV >= (NI * STYLE_NUM_ENTRIES)); // int* src = attrs; // int* baseDest = outValues; // int* dest = baseDest; int indicesIdx = 0; bool haveIndices = false; if (outIndices != NULL) { if (outIndices->length() > NI) haveIndices = true; } // Now lock down the resource object and start pulling stuff from it. res.lock(); // Retrieve the XML attributes, if requested. const size_t NX = xmlParser.getAttributeCount(); size_t ix=0; uint32_t curXmlAttr = xmlParser.getAttributeNameResID(ix); static const ssize_t kXmlBlock = 0x10000000; // Now iterate through all of the attributes that the client has requested, // filling in each with whatever data we can find. size_t offset = 0; ssize_t block = 0; uint32_t typeSetFlags; for (size_t ii=0; ii<NI; ii++) { const uint32_t curIdent = attrs[ii]; // Try to find a value for this attribute... value.dataType = Res_value::TYPE_NULL; value.data = 0; typeSetFlags = 0; config.density = 0; // Skip through XML attributes until the end or the next possible match. while (ix < NX && curIdent > curXmlAttr) { ix++; curXmlAttr = xmlParser.getAttributeNameResID(ix); } // Retrieve the current XML attribute if it matches, and step to next. if (ix < NX && curIdent == curXmlAttr) { block = kXmlBlock; xmlParser.getAttributeValue(ix, &value); ix++; curXmlAttr = xmlParser.getAttributeNameResID(ix); } //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); uint32_t resid = 0; if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. //printf("Resolving attribute reference\n"); ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags, &config); #if THROW_ON_BAD_ID if (newBlock == BAD_INDEX) { jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); return JNI_FALSE; } #endif if (newBlock >= 0) block = newBlock; } // Deal with the special @null value -- it turns back to TYPE_NULL. if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { value.dataType = Res_value::TYPE_NULL; } //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); // Write the final value back to Java. outValues->set(offset+STYLE_TYPE, value.dataType); outValues->set(offset+STYLE_DATA, value.data); // FIXME: This is a pointer! // dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ? res.getTableCookie(block) : NULL; if (block != kXmlBlock) { void* cookie = res.getTableCookie(block); DEBUG_STYLES(LOGI("COOKIE: %p - %x", cookie, (int)(long)cookie)); SkASSERT((int)(long)cookie == (long)cookie); outValues->set(offset+STYLE_ASSET_COOKIE, (int)(long)cookie); } else { outValues->set(offset+STYLE_ASSET_COOKIE, -1); } outValues->set(offset+STYLE_RESOURCE_ID, resid); outValues->set(offset+STYLE_CHANGING_CONFIGURATIONS, typeSetFlags); outValues->set(offset+STYLE_DENSITY, config.density); if (haveIndices && value.dataType != Res_value::TYPE_NULL) { indicesIdx++; outIndices->set(indicesIdx, ii); } offset += STYLE_NUM_ENTRIES; } res.unlock(); if (haveIndices) outIndices->set(0, indicesIdx); return true; }