1 /* libs/graphics/animator/SkDisplayXMLParser.cpp 2 ** 3 ** Copyright 2006, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include "SkDisplayXMLParser.h" 19 #include "SkAnimateMaker.h" 20 #include "SkDisplayApply.h" 21 #include "SkUtils.h" 22 #ifdef SK_DEBUG 23 #include "SkTime.h" 24 #endif 25 26 static char const* const gErrorStrings[] = { 27 "unknown error ", 28 "apply scopes itself", 29 "display tree too deep (circular reference?) ", 30 "element missing parent ", 31 "element type not allowed in parent ", 32 "error adding <data> to <post> ", 33 "error adding to <matrix> ", 34 "error adding to <paint> ", 35 "error adding to <path> ", 36 "error in attribute value ", 37 "error in script ", 38 "expected movie in sink attribute ", 39 "field not in target ", 40 "number of offsets in gradient must match number of colors", 41 "no offset in gradient may be greater than one", 42 "last offset in gradient must be one", 43 "offsets in gradient must be increasing", 44 "first offset in gradient must be zero", 45 "gradient attribute \"points\" must have length of four", 46 "in include ", 47 "in movie ", 48 "include name unknown or missing ", 49 "index out of range ", 50 "movie name unknown or missing ", 51 "no parent available to resolve sink attribute ", 52 "parent element can't contain ", 53 "saveLayer must specify a bounds", 54 "target id not found ", 55 "unexpected type " 56 }; 57 58 SkDisplayXMLParserError::~SkDisplayXMLParserError() { 59 } 60 61 void SkDisplayXMLParserError::getErrorString(SkString* str) const { 62 if (fCode > kUnknownError) 63 str->set(gErrorStrings[fCode - kUnknownError]); 64 else 65 str->reset(); 66 INHERITED::getErrorString(str); 67 } 68 69 void SkDisplayXMLParserError::setInnerError(SkAnimateMaker* parent, const SkString& src) { 70 SkString inner; 71 getErrorString(&inner); 72 inner.prepend(": "); 73 inner.prependS32(getLineNumber()); 74 inner.prepend(", line "); 75 inner.prepend(src); 76 parent->setErrorNoun(inner); 77 } 78 79 80 SkDisplayXMLParser::SkDisplayXMLParser(SkAnimateMaker& maker) 81 : INHERITED(&maker.fError), fMaker(maker), fInInclude(maker.fInInclude), 82 fInSkia(maker.fInInclude), fCurrDisplayable(NULL) 83 { 84 } 85 86 SkDisplayXMLParser::~SkDisplayXMLParser() { 87 if (fCurrDisplayable && fMaker.fChildren.find(fCurrDisplayable) < 0) 88 delete fCurrDisplayable; 89 for (Parent* parPtr = fParents.begin() + 1; parPtr < fParents.end(); parPtr++) { 90 SkDisplayable* displayable = parPtr->fDisplayable; 91 if (displayable == fCurrDisplayable) 92 continue; 93 SkASSERT(fMaker.fChildren.find(displayable) < 0); 94 if (fMaker.fHelpers.find(displayable) < 0) 95 delete displayable; 96 } 97 } 98 99 100 101 bool SkDisplayXMLParser::onAddAttribute(const char name[], const char value[]) { 102 return onAddAttributeLen(name, value, strlen(value)); 103 } 104 105 bool SkDisplayXMLParser::onAddAttributeLen(const char attrName[], const char attrValue[], 106 size_t attrValueLen) 107 { 108 if (fCurrDisplayable == NULL) // this signals we should ignore attributes for this element 109 return strncmp(attrName, "xmlns", sizeof("xmlns") - 1) != 0; 110 SkDisplayable* displayable = fCurrDisplayable; 111 SkDisplayTypes type = fCurrType; 112 113 if (strcmp(attrName, "id") == 0) { 114 if (fMaker.find(attrValue, attrValueLen, NULL)) { 115 fError->setNoun(attrValue, attrValueLen); 116 fError->setCode(SkXMLParserError::kDuplicateIDs); 117 return true; 118 } 119 #ifdef SK_DEBUG 120 displayable->_id.set(attrValue, attrValueLen); 121 displayable->id = displayable->_id.c_str(); 122 #endif 123 fMaker.idsSet(attrValue, attrValueLen, displayable); 124 int parentIndex = fParents.count() - 1; 125 if (parentIndex > 0) { 126 SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable; 127 parent->setChildHasID(); 128 } 129 return false; 130 } 131 const char* name = attrName; 132 const SkMemberInfo* info = SkDisplayType::GetMember(&fMaker, type, &name); 133 if (info == NULL) { 134 fError->setNoun(name); 135 fError->setCode(SkXMLParserError::kUnknownAttributeName); 136 return true; 137 } 138 if (info->setValue(fMaker, NULL, 0, info->getCount(), displayable, info->getType(), attrValue, 139 attrValueLen)) 140 return false; 141 if (fMaker.fError.hasError()) { 142 fError->setNoun(attrValue, attrValueLen); 143 return true; 144 } 145 SkDisplayable* ref = NULL; 146 if (fMaker.find(attrValue, attrValueLen, &ref) == false) { 147 ref = fMaker.createInstance(attrValue, attrValueLen); 148 if (ref == NULL) { 149 fError->setNoun(attrValue, attrValueLen); 150 fError->setCode(SkXMLParserError::kErrorInAttributeValue); 151 return true; 152 } else 153 fMaker.helperAdd(ref); 154 } 155 if (info->fType != SkType_MemberProperty) { 156 fError->setNoun(name); 157 fError->setCode(SkXMLParserError::kUnknownAttributeName); 158 return true; 159 } 160 SkScriptValue scriptValue; 161 scriptValue.fOperand.fDisplayable = ref; 162 scriptValue.fType = ref->getType(); 163 displayable->setProperty(info->propertyIndex(), scriptValue); 164 return false; 165 } 166 167 bool SkDisplayXMLParser::onEndElement(const char elem[]) 168 { 169 int parentIndex = fParents.count() - 1; 170 if (parentIndex >= 0) { 171 Parent& container = fParents[parentIndex]; 172 SkDisplayable* displayable = container.fDisplayable; 173 fMaker.fEndDepth = parentIndex; 174 displayable->onEndElement(fMaker); 175 if (fMaker.fError.hasError()) 176 return true; 177 if (parentIndex > 0) { 178 SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable; 179 bool result = parent->add(fMaker, displayable); 180 if (fMaker.hasError()) 181 return true; 182 if (result == false) { 183 int infoCount; 184 const SkMemberInfo* info = 185 SkDisplayType::GetMembers(&fMaker, fParents[parentIndex - 1].fType, &infoCount); 186 const SkMemberInfo* foundInfo; 187 if ((foundInfo = searchContainer(info, infoCount)) != NULL) { 188 parent->setReference(foundInfo, displayable); 189 // if (displayable->isHelper() == false) 190 fMaker.helperAdd(displayable); 191 } else { 192 fMaker.setErrorCode(SkDisplayXMLParserError::kElementTypeNotAllowedInParent); 193 return true; 194 } 195 } 196 if (parent->childrenNeedDisposing()) 197 delete displayable; 198 } 199 fParents.remove(parentIndex); 200 } 201 fCurrDisplayable = NULL; 202 if (fInInclude == false && strcasecmp(elem, "screenplay") == 0) { 203 if (fMaker.fInMovie == false) { 204 fMaker.fEnableTime = fMaker.getAppTime(); 205 #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING 206 if (fMaker.fDebugTimeBase == (SkMSec) -1) 207 fMaker.fDebugTimeBase = fMaker.fEnableTime; 208 SkString debugOut; 209 SkMSec time = fMaker.getAppTime(); 210 debugOut.appendS32(time - fMaker.fDebugTimeBase); 211 debugOut.append(" onLoad enable="); 212 debugOut.appendS32(fMaker.fEnableTime - fMaker.fDebugTimeBase); 213 SkDebugf("%s\n", debugOut.c_str()); 214 #endif 215 fMaker.fEvents.doEvent(fMaker, SkDisplayEvent::kOnload, NULL); 216 if (fMaker.fError.hasError()) 217 return true; 218 fMaker.fEvents.removeEvent(SkDisplayEvent::kOnload, NULL); 219 220 } 221 fInSkia = false; 222 } 223 return false; 224 } 225 226 bool SkDisplayXMLParser::onStartElement(const char name[]) 227 { 228 return onStartElementLen(name, strlen(name)); 229 } 230 231 bool SkDisplayXMLParser::onStartElementLen(const char name[], size_t len) { 232 fCurrDisplayable = NULL; // init so we'll ignore attributes if we exit early 233 234 if (strncasecmp(name, "screenplay", len) == 0) { 235 fInSkia = true; 236 if (fInInclude == false) 237 fMaker.idsSet(name, len, &fMaker.fScreenplay); 238 return false; 239 } 240 if (fInSkia == false) 241 return false; 242 243 SkDisplayable* displayable = fMaker.createInstance(name, len); 244 if (displayable == NULL) { 245 fError->setNoun(name, len); 246 fError->setCode(SkXMLParserError::kUnknownElement); 247 return true; 248 } 249 SkDisplayTypes type = displayable->getType(); 250 Parent record = { displayable, type }; 251 *fParents.append() = record; 252 if (fParents.count() == 1) 253 fMaker.childrenAdd(displayable); 254 else { 255 Parent* parent = fParents.end() - 2; 256 if (displayable->setParent(parent->fDisplayable)) { 257 fError->setNoun(name, len); 258 getError()->setCode(SkDisplayXMLParserError::kParentElementCantContain); 259 return true; 260 } 261 } 262 263 // set these for subsequent calls to addAttribute() 264 fCurrDisplayable = displayable; 265 fCurrType = type; 266 return false; 267 } 268 269 const SkMemberInfo* SkDisplayXMLParser::searchContainer(const SkMemberInfo* infoBase, 270 int infoCount) { 271 const SkMemberInfo* bestDisplayable = NULL; 272 const SkMemberInfo* lastResort = NULL; 273 for (int index = 0; index < infoCount; index++) { 274 const SkMemberInfo* info = &infoBase[index]; 275 if (info->fType == SkType_BaseClassInfo) { 276 const SkMemberInfo* inherited = info->getInherited(); 277 const SkMemberInfo* result = searchContainer(inherited, info->fCount); 278 if (result != NULL) 279 return result; 280 continue; 281 } 282 Parent* container = fParents.end() - 1; 283 SkDisplayTypes type = (SkDisplayTypes) info->fType; 284 if (type == SkType_MemberProperty) 285 type = info->propertyType(); 286 SkDisplayTypes containerType = container->fType; 287 if (type == containerType && (type == SkType_Rect || type == SkType_Polygon || 288 type == SkType_Array || type == SkType_Int || type == SkType_Bitmap)) 289 goto rectNext; 290 while (type != containerType) { 291 if (containerType == SkType_Displayable) 292 goto next; 293 containerType = SkDisplayType::GetParent(&fMaker, containerType); 294 if (containerType == SkType_Unknown) 295 goto next; 296 } 297 return info; 298 next: 299 if (type == SkType_Drawable || type == SkType_Displayable && 300 container->fDisplayable->isDrawable()) { 301 rectNext: 302 if (fParents.count() > 1) { 303 Parent* parent = fParents.end() - 2; 304 if (info == parent->fDisplayable->preferredChild(type)) 305 bestDisplayable = info; 306 else 307 lastResort = info; 308 } 309 } 310 } 311 if (bestDisplayable) 312 return bestDisplayable; 313 if (lastResort) 314 return lastResort; 315 return NULL; 316 } 317 318 319