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