Home | History | Annotate | Download | only in animator
      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