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