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 "SkAnimateMaker.h"
11#include "SkAnimator.h"
12#include "SkAnimatorScript.h"
13#include "SkDisplayable.h"
14#include "SkDisplayApply.h"
15#include "SkDisplayList.h"
16#include "SkDisplayMovie.h"
17#include "SkDisplayType.h"
18#include "SkExtras.h"
19#include "SkMemberInfo.h"
20#include "SkStream.h"
21#include "SkSystemEventTypes.h"
22#include "SkTime.h"
23
24class DefaultTimeline : public SkAnimator::Timeline {
25    virtual SkMSec getMSecs() const {
26        return SkTime::GetMSecs();
27    }
28} gDefaultTimeline;
29
30SkAnimateMaker::SkAnimateMaker(SkAnimator* animator, SkCanvas* canvas, SkPaint* paint)
31    : fActiveEvent(NULL), fAdjustedStart(0), fCanvas(canvas), fEnableTime(0),
32        fHostEventSinkID(0), fMinimumInterval((SkMSec) -1), fPaint(paint), fParentMaker(NULL),
33        fTimeline(&gDefaultTimeline), fInInclude(false), fInMovie(false),
34        fFirstScriptError(false), fLoaded(false), fIDs(256), fAnimator(animator)
35{
36    fScreenplay.time = 0;
37#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
38    fDebugTimeBase = (SkMSec) -1;
39#endif
40#ifdef SK_DUMP_ENABLED
41    fDumpEvents = fDumpGConditions = fDumpPosts = false;
42#endif
43}
44
45SkAnimateMaker::~SkAnimateMaker() {
46    deleteMembers();
47}
48
49#if 0
50SkMSec SkAnimateMaker::adjustDelay(SkMSec expectedBase, SkMSec delay) {
51    SkMSec appTime = (*fTimeCallBack)();
52    if (appTime)
53        delay -= appTime - expectedBase;
54    if (delay < 0)
55        delay = 0;
56    return delay;
57}
58#endif
59
60void SkAnimateMaker::appendActive(SkActive* active) {
61    fDisplayList.append(active);
62}
63
64void SkAnimateMaker::clearExtraPropertyCallBack(SkDisplayTypes type) {
65    SkExtras** end = fExtras.end();
66    for (SkExtras** extraPtr = fExtras.begin(); extraPtr < end; extraPtr++) {
67        SkExtras* extra = *extraPtr;
68        if (extra->definesType(type)) {
69            extra->fExtraCallBack = NULL;
70            extra->fExtraStorage = NULL;
71            break;
72        }
73    }
74}
75
76bool SkAnimateMaker::computeID(SkDisplayable* displayable, SkDisplayable* parent, SkString* newID) {
77    const char* script;
78  if (findKey(displayable, &script) == false)
79        return true;
80    return SkAnimatorScript::EvaluateString(*this, displayable, parent, script, newID);
81}
82
83SkDisplayable* SkAnimateMaker::createInstance(const char name[], size_t len) {
84    SkDisplayTypes type = SkDisplayType::GetType(this, name, len );
85    if ((int)type >= 0)
86        return SkDisplayType::CreateInstance(this, type);
87    return NULL;
88}
89
90// differs from SkAnimator::decodeStream in that it does not reset error state
91bool SkAnimateMaker::decodeStream(SkStream* stream)
92{
93    SkDisplayXMLParser parser(*this);
94    return parser.parse(*stream);
95}
96
97// differs from SkAnimator::decodeURI in that it does not set URI base
98bool SkAnimateMaker::decodeURI(const char uri[]) {
99//  SkDebugf("animator decode %s\n", uri);
100
101//    SkStream* stream = SkStream::GetURIStream(fPrefix.c_str(), uri);
102    SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(uri));
103    if (stream.get()) {
104        bool success = decodeStream(stream);
105        if (hasError() && fError.hasNoun() == false)
106            fError.setNoun(uri);
107        return success;
108    } else {
109        return false;
110    }
111}
112
113#if defined SK_DEBUG && 0
114//used for the if'd out section of deleteMembers
115#include "SkTSearch.h"
116
117extern "C" {
118    int compare_disp(const void* a, const void* b) {
119        return *(const SkDisplayable**)a - *(const SkDisplayable**)b;
120    }
121}
122#endif
123
124void SkAnimateMaker::delayEnable(SkApply* apply, SkMSec time) {
125    int index = fDelayed.find(apply);
126    if (index < 0) {
127        *fDelayed.append() = apply;
128    }
129
130    (new SkEvent(SK_EventType_Delay, fAnimator->getSinkID()))->postTime(time);
131}
132
133void SkAnimateMaker::deleteMembers() {
134    int index;
135#if defined SK_DEBUG && 0
136    //this code checks to see if helpers are among the children, but it is not complete -
137    //it should check the children of the children
138    int result;
139    SkTDArray<SkDisplayable*> children(fChildren.begin(), fChildren.count());
140    SkQSort(children.begin(), children.count(), sizeof(SkDisplayable*),compare_disp);
141    for (index = 0; index < fHelpers.count(); index++) {
142        SkDisplayable* helper = fHelpers[index];
143        result = SkTSearch(children.begin(), children.count(), helper, sizeof(SkDisplayable*));
144        SkASSERT(result < 0);
145    }
146#endif
147    for (index = 0; index < fChildren.count(); index++) {
148        SkDisplayable* child = fChildren[index];
149        delete child;
150    }
151    for (index = 0; index < fHelpers.count(); index++) {
152        SkDisplayable* helper = fHelpers[index];
153        delete helper;
154    }
155    for (index = 0; index < fExtras.count(); index++) {
156        SkExtras* extras = fExtras[index];
157        delete extras;
158    }
159}
160
161void SkAnimateMaker::doDelayedEvent() {
162    fEnableTime = getAppTime();
163    for (int index = 0; index < fDelayed.count(); ) {
164        SkDisplayable* child = fDelayed[index];
165        SkASSERT(child->isApply());
166        SkApply* apply = (SkApply*) child;
167        apply->interpolate(*this, fEnableTime);
168        if (apply->hasDelayedAnimator())
169            index++;
170        else
171            fDelayed.remove(index);
172    }
173}
174
175bool SkAnimateMaker::doEvent(const SkEvent& event) {
176    return (!fInMovie || fLoaded) && fAnimator->doEvent(event);
177}
178
179#ifdef SK_DUMP_ENABLED
180void SkAnimateMaker::dump(const char* match) {
181        SkTDict<SkDisplayable*>::Iter iter(fIDs);
182        const char* name;
183        SkDisplayable* result;
184        while ((name = iter.next(&result)) != NULL) {
185            if (strcmp(match,name) == 0)
186                result->dump(this);
187        }
188}
189#endif
190
191int SkAnimateMaker::dynamicProperty(SkString& nameStr, SkDisplayable** displayablePtr ) {
192    const char* name = nameStr.c_str();
193    const char* dot = strchr(name, '.');
194    SkASSERT(dot);
195    SkDisplayable* displayable;
196    if (find(name, dot - name, &displayable) == false) {
197        SkASSERT(0);
198        return 0;
199    }
200    const char* fieldName = dot + 1;
201    const SkMemberInfo* memberInfo = displayable->getMember(fieldName);
202    *displayablePtr = displayable;
203    return (int) memberInfo->fOffset;
204}
205
206SkMSec SkAnimateMaker::getAppTime() const {
207    return fTimeline->getMSecs();
208}
209
210#ifdef SK_DEBUG
211SkAnimator* SkAnimateMaker::getRoot()
212{
213    SkAnimateMaker* maker = this;
214    while (maker->fParentMaker)
215        maker = maker->fParentMaker;
216    return maker == this ? NULL : maker->fAnimator;
217}
218#endif
219
220void SkAnimateMaker::helperAdd(SkDisplayable* trackMe) {
221    SkASSERT(fHelpers.find(trackMe) < 0);
222    *fHelpers.append() = trackMe;
223}
224
225void SkAnimateMaker::helperRemove(SkDisplayable* alreadyTracked) {
226    int helperIndex = fHelpers.find(alreadyTracked);
227    if (helperIndex >= 0)
228        fHelpers.remove(helperIndex);
229}
230
231#if 0
232void SkAnimateMaker::loadMovies() {
233    for (SkDisplayable** dispPtr = fMovies.begin(); dispPtr < fMovies.end(); dispPtr++) {
234        SkDisplayable* displayable = *dispPtr;
235        SkASSERT(displayable->getType() == SkType_Movie);
236        SkDisplayMovie* movie = (SkDisplayMovie*) displayable;
237        SkAnimateMaker* movieMaker = movie->fMovie.fMaker;
238        movieMaker->fEvents.doEvent(*movieMaker, SkDisplayEvent::kOnload, NULL);
239        movieMaker->fEvents.removeEvent(SkDisplayEvent::kOnload, NULL);
240        movieMaker->loadMovies();
241    }
242}
243#endif
244
245void SkAnimateMaker::notifyInval() {
246    if (fHostEventSinkID)
247        fAnimator->onEventPost(new SkEvent(SK_EventType_Inval), fHostEventSinkID);
248}
249
250void SkAnimateMaker::notifyInvalTime(SkMSec time) {
251    if (fHostEventSinkID)
252        fAnimator->onEventPostTime(new SkEvent(SK_EventType_Inval), fHostEventSinkID, time);
253}
254
255void SkAnimateMaker::postOnEnd(SkAnimateBase* animate, SkMSec end) {
256        SkEvent evt;
257        evt.setS32("time", animate->getStart() + end);
258        evt.setPtr("anim", animate);
259        evt.setType(SK_EventType_OnEnd);
260        SkEventSinkID sinkID = fAnimator->getSinkID();
261        fAnimator->onEventPost(new SkEvent(evt), sinkID);
262}
263
264void SkAnimateMaker::reset() {
265    deleteMembers();
266    fChildren.reset();
267    fHelpers.reset();
268    fIDs.reset();
269    fEvents.reset();
270    fDisplayList.hardReset();
271}
272
273void SkAnimateMaker::removeActive(SkActive* active) {
274    if (active == NULL)
275        return;
276    fDisplayList.remove(active);
277}
278
279bool SkAnimateMaker::resolveID(SkDisplayable* displayable, SkDisplayable* original) {
280    SkString newID;
281    bool success = computeID(original, NULL, &newID);
282    if (success)
283        setID(displayable, newID);
284    return success;
285}
286
287void SkAnimateMaker::setErrorString() {
288    fErrorString.reset();
289    if (fError.hasError()) {
290        SkString err;
291        if (fFileName.size() > 0)
292            fErrorString.set(fFileName.c_str());
293        else
294            fErrorString.set("screenplay error");
295        int line = fError.getLineNumber();
296        if (line >= 0) {
297            fErrorString.append(", ");
298            fErrorString.append("line ");
299            fErrorString.appendS32(line);
300        }
301        fErrorString.append(": ");
302        fError.getErrorString(&err);
303        fErrorString.append(err);
304#if defined SK_DEBUG
305        SkDebugf("%s\n", fErrorString.c_str());
306#endif
307    }
308}
309
310void SkAnimateMaker::setEnableTime(SkMSec appTime, SkMSec expectedTime) {
311#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
312    SkString debugOut;
313    SkMSec time = getAppTime();
314    debugOut.appendS32(time - fDebugTimeBase);
315    debugOut.append(" set enable old enable=");
316    debugOut.appendS32(fEnableTime - fDebugTimeBase);
317    debugOut.append(" old adjust=");
318    debugOut.appendS32(fAdjustedStart);
319    debugOut.append(" new enable=");
320    debugOut.appendS32(expectedTime - fDebugTimeBase);
321    debugOut.append(" new adjust=");
322    debugOut.appendS32(appTime - expectedTime);
323    SkDebugf("%s\n", debugOut.c_str());
324#endif
325    fAdjustedStart = appTime - expectedTime;
326    fEnableTime = expectedTime;
327    SkDisplayable** firstMovie = fMovies.begin();
328    SkDisplayable** endMovie = fMovies.end();
329    for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) {
330        SkDisplayMovie* movie = (SkDisplayMovie*) *ptr;
331        movie->fMovie.fMaker->setEnableTime(appTime, expectedTime);
332    }
333}
334
335void SkAnimateMaker::setExtraPropertyCallBack(SkDisplayTypes type,
336        SkScriptEngine::_propertyCallBack callBack, void* userStorage) {
337    SkExtras** end = fExtras.end();
338    for (SkExtras** extraPtr = fExtras.begin(); extraPtr < end; extraPtr++) {
339        SkExtras* extra = *extraPtr;
340        if (extra->definesType(type)) {
341            extra->fExtraCallBack = callBack;
342            extra->fExtraStorage = userStorage;
343            break;
344        }
345    }
346}
347
348void SkAnimateMaker::setID(SkDisplayable* displayable, const SkString& newID) {
349    fIDs.set(newID.c_str(), displayable);
350#ifdef SK_DEBUG
351    displayable->_id.set(newID);
352    displayable->id = displayable->_id.c_str();
353#endif
354}
355
356void SkAnimateMaker::setScriptError(const SkScriptEngine& engine) {
357    SkString errorString;
358#ifdef SK_DEBUG
359    engine.getErrorString(&errorString);
360#endif
361    setErrorNoun(errorString);
362    setErrorCode(SkDisplayXMLParserError::kErrorInScript);
363}
364
365bool SkAnimateMaker::GetStep(const char* token, size_t len, void* stepPtr, SkScriptValue* value) {
366    if (SK_LITERAL_STR_EQUAL("step", token, len)) {
367        value->fOperand.fS32 = *(int32_t*) stepPtr;
368        value->fType = SkType_Int;
369        return true;
370    }
371    return false;
372}
373