1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkDisplayXMLParser.h"
11#include "SkAnimateMaker.h"
12#include "SkDisplayApply.h"
13#include "SkUtils.h"
14#ifdef SK_DEBUG
15#include "SkTime.h"
16#endif
17
18static char const* const gErrorStrings[] = {
19    "unknown error ",
20    "apply scopes itself",
21    "display tree too deep (circular reference?) ",
22    "element missing parent ",
23    "element type not allowed in parent ",
24    "error adding <data> to <post> ",
25    "error adding to <matrix> ",
26    "error adding to <paint> ",
27    "error adding to <path> ",
28    "error in attribute value ",
29    "error in script ",
30    "expected movie in sink attribute ",
31    "field not in target ",
32    "number of offsets in gradient must match number of colors",
33    "no offset in gradient may be greater than one",
34    "last offset in gradient must be one",
35    "offsets in gradient must be increasing",
36    "first offset in gradient must be zero",
37    "gradient attribute \"points\" must have length of four",
38    "in include ",
39    "in movie ",
40    "include name unknown or missing ",
41    "index out of range ",
42    "movie name unknown or missing ",
43    "no parent available to resolve sink attribute ",
44    "parent element can't contain ",
45    "saveLayer must specify a bounds",
46    "target id not found ",
47    "unexpected type "
48};
49
50SkDisplayXMLParserError::~SkDisplayXMLParserError() {
51}
52
53void SkDisplayXMLParserError::getErrorString(SkString* str) const {
54    if (fCode > kUnknownError)
55        str->set(gErrorStrings[fCode - kUnknownError]);
56    else
57        str->reset();
58    INHERITED::getErrorString(str);
59}
60
61void SkDisplayXMLParserError::setInnerError(SkAnimateMaker* parent, const SkString& src) {
62    SkString inner;
63    getErrorString(&inner);
64    inner.prepend(": ");
65    inner.prependS32(getLineNumber());
66    inner.prepend(", line ");
67    inner.prepend(src);
68    parent->setErrorNoun(inner);
69}
70
71
72SkDisplayXMLParser::SkDisplayXMLParser(SkAnimateMaker& maker)
73    : INHERITED(&maker.fError), fMaker(maker), fInInclude(maker.fInInclude),
74        fInSkia(maker.fInInclude), fCurrDisplayable(NULL)
75{
76}
77
78SkDisplayXMLParser::~SkDisplayXMLParser() {
79    if (fCurrDisplayable && fMaker.fChildren.find(fCurrDisplayable) < 0)
80        delete fCurrDisplayable;
81    for (Parent* parPtr = fParents.begin() + 1; parPtr < fParents.end(); parPtr++) {
82        SkDisplayable* displayable = parPtr->fDisplayable;
83        if (displayable == fCurrDisplayable)
84            continue;
85        SkASSERT(fMaker.fChildren.find(displayable) < 0);
86        if (fMaker.fHelpers.find(displayable) < 0)
87            delete displayable;
88    }
89}
90
91
92
93bool SkDisplayXMLParser::onAddAttribute(const char name[], const char value[]) {
94    return onAddAttributeLen(name, value, strlen(value));
95}
96
97bool SkDisplayXMLParser::onAddAttributeLen(const char attrName[], const char attrValue[],
98                                        size_t attrValueLen)
99{
100    if (fCurrDisplayable == NULL)    // this signals we should ignore attributes for this element
101        return strncmp(attrName, "xmlns", sizeof("xmlns") - 1) != 0;
102    SkDisplayable*  displayable = fCurrDisplayable;
103    SkDisplayTypes  type = fCurrType;
104
105    if (strcmp(attrName, "id") == 0) {
106        if (fMaker.find(attrValue, attrValueLen, NULL)) {
107            fError->setNoun(attrValue, attrValueLen);
108            fError->setCode(SkXMLParserError::kDuplicateIDs);
109            return true;
110        }
111#ifdef SK_DEBUG
112        displayable->_id.set(attrValue, attrValueLen);
113        displayable->id = displayable->_id.c_str();
114#endif
115        fMaker.idsSet(attrValue, attrValueLen, displayable);
116        int parentIndex = fParents.count() - 1;
117        if (parentIndex > 0) {
118            SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable;
119            parent->setChildHasID();
120        }
121        return false;
122    }
123    const char* name = attrName;
124    const SkMemberInfo* info = SkDisplayType::GetMember(&fMaker, type, &name);
125    if (info == NULL) {
126        fError->setNoun(name);
127        fError->setCode(SkXMLParserError::kUnknownAttributeName);
128        return true;
129    }
130    if (info->setValue(fMaker, NULL, 0, info->getCount(), displayable, info->getType(), attrValue,
131            attrValueLen))
132        return false;
133    if (fMaker.fError.hasError()) {
134        fError->setNoun(attrValue, attrValueLen);
135        return true;
136    }
137    SkDisplayable* ref = NULL;
138    if (fMaker.find(attrValue, attrValueLen, &ref) == false) {
139        ref = fMaker.createInstance(attrValue, attrValueLen);
140        if (ref == NULL) {
141            fError->setNoun(attrValue, attrValueLen);
142            fError->setCode(SkXMLParserError::kErrorInAttributeValue);
143            return true;
144        } else
145            fMaker.helperAdd(ref);
146    }
147    if (info->fType != SkType_MemberProperty) {
148        fError->setNoun(name);
149        fError->setCode(SkXMLParserError::kUnknownAttributeName);
150        return true;
151    }
152    SkScriptValue scriptValue;
153    scriptValue.fOperand.fDisplayable = ref;
154    scriptValue.fType = ref->getType();
155    displayable->setProperty(info->propertyIndex(), scriptValue);
156    return false;
157}
158
159#if defined(SK_BUILD_FOR_WIN32)
160    #define SK_strcasecmp   _stricmp
161    #define SK_strncasecmp  _strnicmp
162#else
163    #define SK_strcasecmp   strcasecmp
164    #define SK_strncasecmp  strncasecmp
165#endif
166
167bool 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->addChild(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 && SK_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
226bool SkDisplayXMLParser::onStartElement(const char name[])
227{
228    return onStartElementLen(name, strlen(name));
229}
230
231bool SkDisplayXMLParser::onStartElementLen(const char name[], size_t len) {
232    fCurrDisplayable = NULL; // init so we'll ignore attributes if we exit early
233
234    if (SK_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
269const 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;
298next:
299        if (type == SkType_Drawable || (type == SkType_Displayable &&
300            container->fDisplayable->isDrawable())) {
301rectNext:
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