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
18 static 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
~SkDisplayXMLParserError()50 SkDisplayXMLParserError::~SkDisplayXMLParserError() {
51 }
52
getErrorString(SkString * str) const53 void 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
setInnerError(SkAnimateMaker * parent,const SkString & src)61 void 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
SkDisplayXMLParser(SkAnimateMaker & maker)72 SkDisplayXMLParser::SkDisplayXMLParser(SkAnimateMaker& maker)
73 : INHERITED(&maker.fError), fMaker(maker), fInInclude(maker.fInInclude),
74 fInSkia(maker.fInInclude), fCurrDisplayable(nullptr)
75 {
76 }
77
~SkDisplayXMLParser()78 SkDisplayXMLParser::~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
onAddAttribute(const char name[],const char value[])93 bool SkDisplayXMLParser::onAddAttribute(const char name[], const char value[]) {
94 return onAddAttributeLen(name, value, strlen(value));
95 }
96
onAddAttributeLen(const char attrName[],const char attrValue[],size_t attrValueLen)97 bool SkDisplayXMLParser::onAddAttributeLen(const char attrName[], const char attrValue[],
98 size_t attrValueLen)
99 {
100 if (fCurrDisplayable == nullptr) // 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, nullptr)) {
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 == nullptr) {
126 fError->setNoun(name);
127 fError->setCode(SkXMLParserError::kUnknownAttributeName);
128 return true;
129 }
130 if (info->setValue(fMaker, nullptr, 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 = nullptr;
138 if (fMaker.find(attrValue, attrValueLen, &ref) == false) {
139 ref = fMaker.createInstance(attrValue, attrValueLen);
140 if (ref == nullptr) {
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
onEndElement(const char elem[])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->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)) != nullptr) {
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 = nullptr;
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, nullptr);
216 if (fMaker.fError.hasError())
217 return true;
218 fMaker.fEvents.removeEvent(SkDisplayEvent::kOnload, nullptr);
219
220 }
221 fInSkia = false;
222 }
223 return false;
224 }
225
onStartElement(const char name[])226 bool SkDisplayXMLParser::onStartElement(const char name[])
227 {
228 return onStartElementLen(name, strlen(name));
229 }
230
onStartElementLen(const char name[],size_t len)231 bool SkDisplayXMLParser::onStartElementLen(const char name[], size_t len) {
232 fCurrDisplayable = nullptr; // 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 == nullptr) {
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
searchContainer(const SkMemberInfo * infoBase,int infoCount)269 const SkMemberInfo* SkDisplayXMLParser::searchContainer(const SkMemberInfo* infoBase,
270 int infoCount) {
271 const SkMemberInfo* bestDisplayable = nullptr;
272 const SkMemberInfo* lastResort = nullptr;
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 != nullptr)
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 nullptr;
316 }
317