diff options
Diffstat (limited to 'skia/animator/SkDisplayXMLParser.cpp')
-rw-r--r-- | skia/animator/SkDisplayXMLParser.cpp | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/skia/animator/SkDisplayXMLParser.cpp b/skia/animator/SkDisplayXMLParser.cpp new file mode 100644 index 0000000..39c4a39 --- /dev/null +++ b/skia/animator/SkDisplayXMLParser.cpp @@ -0,0 +1,318 @@ +/* libs/graphics/animator/SkDisplayXMLParser.cpp +** +** Copyright 2006, Google Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include "SkDisplayXMLParser.h" +#include "SkAnimateMaker.h" +#include "SkDisplayApply.h" +#include "SkUtils.h" +#ifdef SK_DEBUG +#include "SkTime.h" +#endif + +static char const* const gErrorStrings[] = { + "unknown error ", + "apply scopes itself", + "display tree too deep (circular reference?) ", + "element missing parent ", + "element type not allowed in parent ", + "error adding <data> to <post> ", + "error adding to <matrix> ", + "error adding to <paint> ", + "error adding to <path> ", + "error in attribute value ", + "error in script ", + "expected movie in sink attribute ", + "field not in target ", + "number of offsets in gradient must match number of colors", + "no offset in gradient may be greater than one", + "last offset in gradient must be one", + "offsets in gradient must be increasing", + "first offset in gradient must be zero", + "gradient attribute \"points\" must have length of four", + "in include ", + "in movie ", + "include name unknown or missing ", + "index out of range ", + "movie name unknown or missing ", + "no parent available to resolve sink attribute ", + "parent element can't contain ", + "saveLayer must specify a bounds", + "target id not found ", + "unexpected type " +}; + +SkDisplayXMLParserError::~SkDisplayXMLParserError() { +} + +void SkDisplayXMLParserError::getErrorString(SkString* str) const { + if (fCode > kUnknownError) + str->set(gErrorStrings[fCode - kUnknownError]); + else + str->reset(); + INHERITED::getErrorString(str); +} + +void SkDisplayXMLParserError::setInnerError(SkAnimateMaker* parent, const SkString& src) { + SkString inner; + getErrorString(&inner); + inner.prepend(": "); + inner.prependS32(getLineNumber()); + inner.prepend(", line "); + inner.prepend(src); + parent->setErrorNoun(inner); +} + + +SkDisplayXMLParser::SkDisplayXMLParser(SkAnimateMaker& maker) + : INHERITED(&maker.fError), fMaker(maker), fInInclude(maker.fInInclude), + fInSkia(maker.fInInclude), fCurrDisplayable(NULL) +{ +} + +SkDisplayXMLParser::~SkDisplayXMLParser() { + if (fCurrDisplayable && fMaker.fChildren.find(fCurrDisplayable) < 0) + delete fCurrDisplayable; + for (Parent* parPtr = fParents.begin() + 1; parPtr < fParents.end(); parPtr++) { + SkDisplayable* displayable = parPtr->fDisplayable; + if (displayable == fCurrDisplayable) + continue; + SkASSERT(fMaker.fChildren.find(displayable) < 0); + if (fMaker.fHelpers.find(displayable) < 0) + delete displayable; + } +} + + + +bool SkDisplayXMLParser::onAddAttribute(const char name[], const char value[]) { + return onAddAttributeLen(name, value, strlen(value)); +} + +bool SkDisplayXMLParser::onAddAttributeLen(const char attrName[], const char attrValue[], + size_t attrValueLen) +{ + if (fCurrDisplayable == NULL) // this signals we should ignore attributes for this element + return strncmp(attrName, "xmlns", sizeof("xmlns") - 1) != 0; + SkDisplayable* displayable = fCurrDisplayable; + SkDisplayTypes type = fCurrType; + + if (strcmp(attrName, "id") == 0) { + if (fMaker.find(attrValue, attrValueLen, NULL)) { + fError->setNoun(attrValue, attrValueLen); + fError->setCode(SkXMLParserError::kDuplicateIDs); + return true; + } +#ifdef SK_DEBUG + displayable->_id.set(attrValue, attrValueLen); + displayable->id = displayable->_id.c_str(); +#endif + fMaker.idsSet(attrValue, attrValueLen, displayable); + int parentIndex = fParents.count() - 1; + if (parentIndex > 0) { + SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable; + parent->setChildHasID(); + } + return false; + } + const char* name = attrName; + const SkMemberInfo* info = SkDisplayType::GetMember(&fMaker, type, &name); + if (info == NULL) { + fError->setNoun(name); + fError->setCode(SkXMLParserError::kUnknownAttributeName); + return true; + } + if (info->setValue(fMaker, NULL, 0, info->getCount(), displayable, info->getType(), attrValue, + attrValueLen)) + return false; + if (fMaker.fError.hasError()) { + fError->setNoun(attrValue, attrValueLen); + return true; + } + SkDisplayable* ref = NULL; + if (fMaker.find(attrValue, attrValueLen, &ref) == false) { + ref = fMaker.createInstance(attrValue, attrValueLen); + if (ref == NULL) { + fError->setNoun(attrValue, attrValueLen); + fError->setCode(SkXMLParserError::kErrorInAttributeValue); + return true; + } else + fMaker.helperAdd(ref); + } + if (info->fType != SkType_MemberProperty) { + fError->setNoun(name); + fError->setCode(SkXMLParserError::kUnknownAttributeName); + return true; + } + SkScriptValue scriptValue; + scriptValue.fOperand.fDisplayable = ref; + scriptValue.fType = ref->getType(); + displayable->setProperty(info->propertyIndex(), scriptValue); + return false; +} + +bool SkDisplayXMLParser::onEndElement(const char elem[]) +{ + int parentIndex = fParents.count() - 1; + if (parentIndex >= 0) { + Parent& container = fParents[parentIndex]; + SkDisplayable* displayable = container.fDisplayable; + fMaker.fEndDepth = parentIndex; + displayable->onEndElement(fMaker); + if (fMaker.fError.hasError()) + return true; + if (parentIndex > 0) { + SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable; + bool result = parent->add(fMaker, displayable); + if (fMaker.hasError()) + return true; + if (result == false) { + int infoCount; + const SkMemberInfo* info = + SkDisplayType::GetMembers(&fMaker, fParents[parentIndex - 1].fType, &infoCount); + const SkMemberInfo* foundInfo; + if ((foundInfo = searchContainer(info, infoCount)) != NULL) { + parent->setReference(foundInfo, displayable); + // if (displayable->isHelper() == false) + fMaker.helperAdd(displayable); + } else { + fMaker.setErrorCode(SkDisplayXMLParserError::kElementTypeNotAllowedInParent); + return true; + } + } + if (parent->childrenNeedDisposing()) + delete displayable; + } + fParents.remove(parentIndex); + } + fCurrDisplayable = NULL; + if (fInInclude == false && strcasecmp(elem, "screenplay") == 0) { + if (fMaker.fInMovie == false) { + fMaker.fEnableTime = fMaker.getAppTime(); +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + if (fMaker.fDebugTimeBase == (SkMSec) -1) + fMaker.fDebugTimeBase = fMaker.fEnableTime; + SkString debugOut; + SkMSec time = fMaker.getAppTime(); + debugOut.appendS32(time - fMaker.fDebugTimeBase); + debugOut.append(" onLoad enable="); + debugOut.appendS32(fMaker.fEnableTime - fMaker.fDebugTimeBase); + SkDebugf("%s\n", debugOut.c_str()); +#endif + fMaker.fEvents.doEvent(fMaker, SkDisplayEvent::kOnload, NULL); + if (fMaker.fError.hasError()) + return true; + fMaker.fEvents.removeEvent(SkDisplayEvent::kOnload, NULL); + + } + fInSkia = false; + } + return false; +} + +bool SkDisplayXMLParser::onStartElement(const char name[]) +{ + return onStartElementLen(name, strlen(name)); +} + +bool SkDisplayXMLParser::onStartElementLen(const char name[], size_t len) { + fCurrDisplayable = NULL; // init so we'll ignore attributes if we exit early + + if (strncasecmp(name, "screenplay", len) == 0) { + fInSkia = true; + if (fInInclude == false) + fMaker.idsSet(name, len, &fMaker.fScreenplay); + return false; + } + if (fInSkia == false) + return false; + + SkDisplayable* displayable = fMaker.createInstance(name, len); + if (displayable == NULL) { + fError->setNoun(name, len); + fError->setCode(SkXMLParserError::kUnknownElement); + return true; + } + SkDisplayTypes type = displayable->getType(); + Parent record = { displayable, type }; + *fParents.append() = record; + if (fParents.count() == 1) + fMaker.childrenAdd(displayable); + else { + Parent* parent = fParents.end() - 2; + if (displayable->setParent(parent->fDisplayable)) { + fError->setNoun(name, len); + getError()->setCode(SkDisplayXMLParserError::kParentElementCantContain); + return true; + } + } + + // set these for subsequent calls to addAttribute() + fCurrDisplayable = displayable; + fCurrType = type; + return false; +} + +const SkMemberInfo* SkDisplayXMLParser::searchContainer(const SkMemberInfo* infoBase, + int infoCount) { + const SkMemberInfo* bestDisplayable = NULL; + const SkMemberInfo* lastResort = NULL; + for (int index = 0; index < infoCount; index++) { + const SkMemberInfo* info = &infoBase[index]; + if (info->fType == SkType_BaseClassInfo) { + const SkMemberInfo* inherited = info->getInherited(); + const SkMemberInfo* result = searchContainer(inherited, info->fCount); + if (result != NULL) + return result; + continue; + } + Parent* container = fParents.end() - 1; + SkDisplayTypes type = (SkDisplayTypes) info->fType; + if (type == SkType_MemberProperty) + type = info->propertyType(); + SkDisplayTypes containerType = container->fType; + if (type == containerType && (type == SkType_Rect || type == SkType_Polygon || + type == SkType_Array || type == SkType_Int || type == SkType_Bitmap)) + goto rectNext; + while (type != containerType) { + if (containerType == SkType_Displayable) + goto next; + containerType = SkDisplayType::GetParent(&fMaker, containerType); + if (containerType == SkType_Unknown) + goto next; + } + return info; +next: + if (type == SkType_Drawable || type == SkType_Displayable && + container->fDisplayable->isDrawable()) { +rectNext: + if (fParents.count() > 1) { + Parent* parent = fParents.end() - 2; + if (info == parent->fDisplayable->preferredChild(type)) + bestDisplayable = info; + else + lastResort = info; + } + } + } + if (bestDisplayable) + return bestDisplayable; + if (lastResort) + return lastResort; + return NULL; +} + + |