|
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 "SkDisplayPost.h" |
|
11 #include "SkAnimateMaker.h" |
|
12 #include "SkAnimator.h" |
|
13 #include "SkDisplayMovie.h" |
|
14 #include "SkPostParts.h" |
|
15 #include "SkScript.h" |
|
16 #ifdef SK_DEBUG |
|
17 #include "SkDump.h" |
|
18 #include "SkTime.h" |
|
19 #endif |
|
20 |
|
21 enum SkPost_Properties { |
|
22 SK_PROPERTY(target), |
|
23 SK_PROPERTY(type) |
|
24 }; |
|
25 |
|
26 #if SK_USE_CONDENSED_INFO == 0 |
|
27 |
|
28 const SkMemberInfo SkPost::fInfo[] = { |
|
29 SK_MEMBER(delay, MSec), |
|
30 // SK_MEMBER(initialized, Boolean), |
|
31 SK_MEMBER(mode, EventMode), |
|
32 SK_MEMBER(sink, String), |
|
33 SK_MEMBER_PROPERTY(target, String), |
|
34 SK_MEMBER_PROPERTY(type, String) |
|
35 }; |
|
36 |
|
37 #endif |
|
38 |
|
39 DEFINE_GET_MEMBER(SkPost); |
|
40 |
|
41 SkPost::SkPost() : delay(0), /*initialized(SkBool(-1)), */ mode(kImmediate), fMaker(NULL), |
|
42 fSinkID(0), fTargetMaker(NULL), fChildHasID(false), fDirty(false) { |
|
43 } |
|
44 |
|
45 SkPost::~SkPost() { |
|
46 for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) |
|
47 delete *part; |
|
48 } |
|
49 |
|
50 bool SkPost::addChild(SkAnimateMaker& , SkDisplayable* child) { |
|
51 SkASSERT(child && child->isDataInput()); |
|
52 SkDataInput* part = (SkDataInput*) child; |
|
53 *fParts.append() = part; |
|
54 return true; |
|
55 } |
|
56 |
|
57 bool SkPost::childrenNeedDisposing() const { |
|
58 return false; |
|
59 } |
|
60 |
|
61 void SkPost::dirty() { |
|
62 fDirty = true; |
|
63 } |
|
64 |
|
65 #ifdef SK_DUMP_ENABLED |
|
66 void SkPost::dump(SkAnimateMaker* maker) { |
|
67 dumpBase(maker); |
|
68 SkString* eventType = new SkString(); |
|
69 fEvent.getType(eventType); |
|
70 if (eventType->equals("user")) { |
|
71 const char* target = fEvent.findString("id"); |
|
72 SkDebugf("target=\"%s\" ", target); |
|
73 } |
|
74 else |
|
75 SkDebugf("type=\"%s\" ", eventType->c_str()); |
|
76 delete eventType; |
|
77 |
|
78 if (delay > 0) { |
|
79 SkDebugf("delay=\"%g\" ", SkScalarToFloat(SkScalarDiv(delay, 1000))); |
|
80 } |
|
81 // if (initialized == false) |
|
82 // SkDebugf("(uninitialized) "); |
|
83 SkString string; |
|
84 SkDump::GetEnumString(SkType_EventMode, mode, &string); |
|
85 if (!string.equals("immediate")) |
|
86 SkDebugf("mode=\"%s\" ", string.c_str()); |
|
87 // !!! could enhance this to search through make hierarchy to show name of sink |
|
88 if (sink.size() > 0) { |
|
89 SkDebugf("sink=\"%s\" sinkID=\"%d\" ", sink.c_str(), fSinkID); |
|
90 } else if (fSinkID != maker->getAnimator()->getSinkID() && fSinkID != 0) { |
|
91 SkDebugf("sinkID=\"%d\" ", fSinkID); |
|
92 } |
|
93 const SkMetaData& meta = fEvent.getMetaData(); |
|
94 SkMetaData::Iter iter(meta); |
|
95 SkMetaData::Type type; |
|
96 int number; |
|
97 const char* name; |
|
98 bool closedYet = false; |
|
99 SkDisplayList::fIndent += 4; |
|
100 //this seems to work, but kinda hacky |
|
101 //for some reason the last part is id, which i don't want |
|
102 //and the parts seem to be in the reverse order from the one in which we find the |
|
103 //data itself |
|
104 //SkDataInput** ptr = fParts.end(); |
|
105 //SkDataInput* data; |
|
106 //const char* ID; |
|
107 while ((name = iter.next(&type, &number)) != NULL) { |
|
108 //ptr--; |
|
109 if (strcmp(name, "id") == 0) |
|
110 continue; |
|
111 if (closedYet == false) { |
|
112 SkDebugf(">\n"); |
|
113 closedYet = true; |
|
114 } |
|
115 //data = *ptr; |
|
116 //if (data->id) |
|
117 // ID = data->id; |
|
118 //else |
|
119 // ID = ""; |
|
120 SkDebugf("%*s<data name=\"%s\" ", SkDisplayList::fIndent, "", name); |
|
121 switch (type) { |
|
122 case SkMetaData::kS32_Type: { |
|
123 int32_t s32; |
|
124 meta.findS32(name, &s32); |
|
125 SkDebugf("int=\"%d\" ", s32); |
|
126 } break; |
|
127 case SkMetaData::kScalar_Type: { |
|
128 SkScalar scalar; |
|
129 meta.findScalar(name, &scalar); |
|
130 SkDebugf("float=\"%g\" ", SkScalarToFloat(scalar)); |
|
131 } break; |
|
132 case SkMetaData::kString_Type: |
|
133 SkDebugf("string=\"%s\" ", meta.findString(name)); |
|
134 break; |
|
135 case SkMetaData::kPtr_Type: {//when do we have a pointer |
|
136 void* ptr; |
|
137 meta.findPtr(name, &ptr); |
|
138 SkDebugf("0x%08x ", ptr); |
|
139 } break; |
|
140 case SkMetaData::kBool_Type: { |
|
141 bool boolean; |
|
142 meta.findBool(name, &boolean); |
|
143 SkDebugf("boolean=\"%s\" ", boolean ? "true " : "false "); |
|
144 } break; |
|
145 default: |
|
146 break; |
|
147 } |
|
148 SkDebugf("/>\n"); |
|
149 //ptr++; |
|
150 /* perhaps this should only be done in the case of a pointer? |
|
151 SkDisplayable* displayable; |
|
152 if (maker->find(name, &displayable)) |
|
153 displayable->dump(maker); |
|
154 else |
|
155 SkDebugf("\n");*/ |
|
156 } |
|
157 SkDisplayList::fIndent -= 4; |
|
158 if (closedYet) |
|
159 dumpEnd(maker); |
|
160 else |
|
161 SkDebugf("/>\n"); |
|
162 |
|
163 } |
|
164 #endif |
|
165 |
|
166 bool SkPost::enable(SkAnimateMaker& maker ) { |
|
167 if (maker.hasError()) |
|
168 return true; |
|
169 if (fDirty) { |
|
170 if (sink.size() > 0) |
|
171 findSinkID(); |
|
172 if (fChildHasID) { |
|
173 SkString preserveID(fEvent.findString("id")); |
|
174 fEvent.getMetaData().reset(); |
|
175 if (preserveID.size() > 0) |
|
176 fEvent.setString("id", preserveID); |
|
177 for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) { |
|
178 if ((*part)->add()) |
|
179 maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingDataToPost); |
|
180 } |
|
181 } |
|
182 fDirty = false; |
|
183 } |
|
184 #ifdef SK_DUMP_ENABLED |
|
185 if (maker.fDumpPosts) { |
|
186 SkDebugf("post enable: "); |
|
187 dump(&maker); |
|
188 } |
|
189 #if defined SK_DEBUG_ANIMATION_TIMING |
|
190 SkString debugOut; |
|
191 SkMSec time = maker.getAppTime(); |
|
192 debugOut.appendS32(time - maker.fDebugTimeBase); |
|
193 debugOut.append(" post id="); |
|
194 debugOut.append(_id); |
|
195 debugOut.append(" enable="); |
|
196 debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase); |
|
197 debugOut.append(" delay="); |
|
198 debugOut.appendS32(delay); |
|
199 #endif |
|
200 #endif |
|
201 // SkMSec adjustedDelay = maker.adjustDelay(maker.fEnableTime, delay); |
|
202 SkMSec futureTime = maker.fEnableTime + delay; |
|
203 fEvent.setFast32(futureTime); |
|
204 #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING |
|
205 debugOut.append(" future="); |
|
206 debugOut.appendS32(futureTime - maker.fDebugTimeBase); |
|
207 SkDebugf("%s\n", debugOut.c_str()); |
|
208 #endif |
|
209 SkEventSinkID targetID = fSinkID; |
|
210 bool isAnimatorEvent = true; |
|
211 SkAnimator* anim = maker.getAnimator(); |
|
212 if (targetID == 0) { |
|
213 isAnimatorEvent = fEvent.findString("id") != NULL; |
|
214 if (isAnimatorEvent) |
|
215 targetID = anim->getSinkID(); |
|
216 else if (maker.fHostEventSinkID) |
|
217 targetID = maker.fHostEventSinkID; |
|
218 else |
|
219 return true; |
|
220 } else |
|
221 anim = fTargetMaker->getAnimator(); |
|
222 if (delay == 0) { |
|
223 if (isAnimatorEvent && mode == kImmediate) |
|
224 fTargetMaker->doEvent(fEvent); |
|
225 else |
|
226 anim->onEventPost(new SkEvent(fEvent), targetID); |
|
227 } else |
|
228 anim->onEventPostTime(new SkEvent(fEvent), targetID, futureTime); |
|
229 return true; |
|
230 } |
|
231 |
|
232 void SkPost::findSinkID() { |
|
233 // get the next delimiter '.' if any |
|
234 fTargetMaker = fMaker; |
|
235 const char* ch = sink.c_str(); |
|
236 do { |
|
237 const char* end = strchr(ch, '.'); |
|
238 size_t len = end ? (size_t) (end - ch) : strlen(ch); |
|
239 SkDisplayable* displayable = NULL; |
|
240 if (SK_LITERAL_STR_EQUAL("parent", ch, len)) { |
|
241 if (fTargetMaker->fParentMaker) |
|
242 fTargetMaker = fTargetMaker->fParentMaker; |
|
243 else { |
|
244 fTargetMaker->setErrorCode(SkDisplayXMLParserError::kNoParentAvailable); |
|
245 return; |
|
246 } |
|
247 } else { |
|
248 fTargetMaker->find(ch, len, &displayable); |
|
249 if (displayable == NULL || displayable->getType() != SkType_Movie) { |
|
250 fTargetMaker->setErrorCode(SkDisplayXMLParserError::kExpectedMovie); |
|
251 return; |
|
252 } |
|
253 SkDisplayMovie* movie = (SkDisplayMovie*) displayable; |
|
254 fTargetMaker = movie->fMovie.fMaker; |
|
255 } |
|
256 if (end == NULL) |
|
257 break; |
|
258 ch = ++end; |
|
259 } while (true); |
|
260 SkAnimator* anim = fTargetMaker->getAnimator(); |
|
261 fSinkID = anim->getSinkID(); |
|
262 } |
|
263 |
|
264 bool SkPost::hasEnable() const { |
|
265 return true; |
|
266 } |
|
267 |
|
268 void SkPost::onEndElement(SkAnimateMaker& maker) { |
|
269 fTargetMaker = fMaker = &maker; |
|
270 if (fChildHasID == false) { |
|
271 for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) |
|
272 delete *part; |
|
273 fParts.reset(); |
|
274 } |
|
275 } |
|
276 |
|
277 void SkPost::setChildHasID() { |
|
278 fChildHasID = true; |
|
279 } |
|
280 |
|
281 bool SkPost::setProperty(int index, SkScriptValue& value) { |
|
282 SkASSERT(value.fType == SkType_String); |
|
283 SkString* string = value.fOperand.fString; |
|
284 switch(index) { |
|
285 case SK_PROPERTY(target): { |
|
286 fEvent.setType("user"); |
|
287 fEvent.setString("id", *string); |
|
288 mode = kImmediate; |
|
289 } break; |
|
290 case SK_PROPERTY(type): |
|
291 fEvent.setType(*string); |
|
292 break; |
|
293 default: |
|
294 SkASSERT(0); |
|
295 return false; |
|
296 } |
|
297 return true; |
|
298 } |