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