|
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 |
|
50 SkDisplayXMLParserError::~SkDisplayXMLParserError() { |
|
51 } |
|
52 |
|
53 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 |
|
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 |
|
72 SkDisplayXMLParser::SkDisplayXMLParser(SkAnimateMaker& maker) |
|
73 : INHERITED(&maker.fError), fMaker(maker), fInInclude(maker.fInInclude), |
|
74 fInSkia(maker.fInInclude), fCurrDisplayable(NULL) |
|
75 { |
|
76 } |
|
77 |
|
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 |
|
93 bool SkDisplayXMLParser::onAddAttribute(const char name[], const char value[]) { |
|
94 return onAddAttributeLen(name, value, strlen(value)); |
|
95 } |
|
96 |
|
97 bool 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 |
|
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)) != 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 |
|
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 (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 |
|
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 } |