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 
SkPost()41 SkPost::SkPost() : delay(0), /*initialized(SkBool(-1)), */ mode(kImmediate), fMaker(nullptr),
42     fSinkID(0), fTargetMaker(nullptr), fChildHasID(false), fDirty(false) {
43 }
44 
~SkPost()45 SkPost::~SkPost() {
46     for (SkDataInput** part = fParts.begin(); part < fParts.end();  part++)
47         delete *part;
48 }
49 
addChild(SkAnimateMaker &,SkDisplayable * child)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 
childrenNeedDisposing() const57 bool SkPost::childrenNeedDisposing() const {
58     return false;
59 }
60 
dirty()61 void SkPost::dirty() {
62     fDirty = true;
63 }
64 
65 #ifdef SK_DUMP_ENABLED
dump(SkAnimateMaker * maker)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\" ", delay * 0.001);
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)) != nullptr) {
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 
enable(SkAnimateMaker & maker)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") != nullptr;
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 
findSinkID()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 = nullptr;
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 == nullptr || 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 == nullptr)
257             break;
258         ch = ++end;
259     } while (true);
260     SkAnimator* anim = fTargetMaker->getAnimator();
261     fSinkID = anim->getSinkID();
262 }
263 
hasEnable() const264 bool SkPost::hasEnable() const {
265     return true;
266 }
267 
onEndElement(SkAnimateMaker & maker)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 
setChildHasID()277 void SkPost::setChildHasID() {
278     fChildHasID = true;
279 }
280 
setProperty(int index,SkScriptValue & value)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 }
299