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 "SkAnimator.h"
11 #include "SkAnimateMaker.h"
12 #include "SkCanvas.h"
13 #include "SkDisplayApply.h"
14 #include "SkDisplayMovie.h"
15 #include "SkDisplayTypes.h"
16 #include "SkDisplayXMLParser.h"
17 #include "SkStream.h"
18 #include "SkScript.h"
19 #include "SkScript2.h" // compiled script experiment
20 #include "SkSystemEventTypes.h"
21 #include "SkTypedArray.h"
22 #ifdef SK_BUILD_FOR_ANDROID
23 #include "SkDrawExtraPathEffect.h"
24 #endif
25 #ifdef SK_DEBUG
26 #include "SkTime.h"
27 #endif
28
29 #if defined SK_BUILD_FOR_WIN32 && defined SK_DEBUG
30 #define _static
31 extern const char gMathPrimerText[];
32 extern const char gMathPrimerBinary[];
33 #else
34 #define _static static
35 #endif
36
37 _static const char gMathPrimerText[] =
38 "<screenplay>"
39 "<Math id=\"Math\"/>"
40 "<Number id=\"Number\"/>"
41 "</screenplay>";
42
43 #define gMathPrimer gMathPrimerText
44
SkAnimator()45 SkAnimator::SkAnimator() : fMaker(nullptr) {
46 initialize();
47 }
48
~SkAnimator()49 SkAnimator::~SkAnimator() { delete fMaker; }
50
addExtras(SkExtras * extras)51 void SkAnimator::addExtras(SkExtras* extras) {
52 *fMaker->fExtras.append() = extras;
53 }
54
appendStream(SkStream * stream)55 bool SkAnimator::appendStream(SkStream* stream) {
56 return decodeStream(stream);
57 }
58
decodeMemory(const void * buffer,size_t size)59 bool SkAnimator::decodeMemory(const void* buffer, size_t size)
60 {
61 fMaker->fFileName.reset();
62 SkDisplayXMLParser parser(*fMaker);
63 return parser.parse((const char*)buffer, size);
64 }
65
decodeStream(SkStream * stream)66 bool SkAnimator::decodeStream(SkStream* stream)
67 {
68 SkDisplayXMLParser parser(*fMaker);
69 bool result = parser.parse(*stream);
70 fMaker->setErrorString();
71 return result;
72 }
73
decodeDOM(const SkDOM & dom,const SkDOMNode * node)74 bool SkAnimator::decodeDOM(const SkDOM& dom, const SkDOMNode* node)
75 {
76 fMaker->fFileName.reset();
77 SkDisplayXMLParser parser(*fMaker);
78 return parser.parse(dom, node);
79 }
80
decodeURI(const char uri[])81 bool SkAnimator::decodeURI(const char uri[]) {
82 // SkDebugf("animator decode %s\n", uri);
83
84 // SkStream* stream = SkStream::GetURIStream(fMaker->fPrefix.c_str(), uri);
85 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(uri));
86 if (stream.get()) {
87 this->setURIBase(uri);
88 return decodeStream(stream);
89 } else {
90 return false;
91 }
92 }
93
doCharEvent(SkUnichar code)94 bool SkAnimator::doCharEvent(SkUnichar code) {
95 if (code == 0)
96 return false;
97 struct SkEventState state;
98 state.fCode = code;
99 fMaker->fEnableTime = fMaker->getAppTime();
100 bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyChar, &state);
101 fMaker->notifyInval();
102 return result;
103 }
104
doClickEvent(int clickState,SkScalar x,SkScalar y)105 bool SkAnimator::doClickEvent(int clickState, SkScalar x, SkScalar y) {
106 SkASSERT(clickState >= 0 && clickState <= 2);
107 struct SkEventState state;
108 state.fX = x;
109 state.fY = y;
110 fMaker->fEnableTime = fMaker->getAppTime();
111 bool result = fMaker->fEvents.doEvent(*fMaker,
112 clickState == 0 ? SkDisplayEvent::kMouseDown :
113 clickState == 1 ? SkDisplayEvent::kMouseDrag :
114 SkDisplayEvent::kMouseUp, &state);
115 fMaker->notifyInval();
116 return result;
117 }
118
doKeyEvent(SkKey code)119 bool SkAnimator::doKeyEvent(SkKey code) {
120 if (code == 0)
121 return false;
122 struct SkEventState state;
123 state.fCode = code;
124 fMaker->fEnableTime = fMaker->getAppTime();
125 bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyPress, &state);
126 fMaker->notifyInval();
127 return result;
128 }
129
doKeyUpEvent(SkKey code)130 bool SkAnimator::doKeyUpEvent(SkKey code) {
131 if (code == 0)
132 return false;
133 struct SkEventState state;
134 state.fCode = code;
135 fMaker->fEnableTime = fMaker->getAppTime();
136 bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyPressUp, &state);
137 fMaker->notifyInval();
138 return result;
139 }
140
doUserEvent(const SkEvent & evt)141 bool SkAnimator::doUserEvent(const SkEvent& evt) {
142 fMaker->fEnableTime = fMaker->getAppTime();
143 return onEvent(evt);
144 }
145
draw(SkCanvas * canvas,SkPaint * paint,SkMSec time)146 SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkPaint* paint, SkMSec time) {
147 if (paint == nullptr)
148 return draw(canvas, time);
149 fMaker->fScreenplay.time = time;
150 fMaker->fCanvas = canvas;
151 fMaker->fPaint = paint;
152 fMaker->fDisplayList.fHasUnion = false;
153 int result = fMaker->fDisplayList.draw(*fMaker, time);
154 if (result)
155 result += fMaker->fDisplayList.fHasUnion;
156 return (DifferenceType) result;
157 }
158
draw(SkCanvas * canvas,SkMSec time)159 SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkMSec time) {
160 SkPaint paint;
161 return draw(canvas, &paint, time);
162 }
163
164 #ifdef SK_DEBUG
eventDone(const SkEvent &)165 void SkAnimator::eventDone(const SkEvent& ) {
166 }
167 #endif
168
findClickEvent(SkScalar x,SkScalar y)169 bool SkAnimator::findClickEvent(SkScalar x, SkScalar y) {
170 struct SkEventState state;
171 state.fDisable = true;
172 state.fX = x;
173 state.fY = y;
174 fMaker->fEnableTime = fMaker->getAppTime();
175 bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kMouseDown, &state);
176 fMaker->notifyInval();
177 return result;
178 }
179
getAnimator(const SkDisplayable * displayable) const180 const SkAnimator* SkAnimator::getAnimator(const SkDisplayable* displayable) const {
181 if (displayable->getType() != SkType_Movie)
182 return nullptr;
183 const SkDisplayMovie* movie = (const SkDisplayMovie*) displayable;
184 return movie->getAnimator();
185 }
186
getElement(const char * id)187 const SkDisplayable* SkAnimator::getElement(const char* id) {
188 SkDisplayable* element;
189 if (fMaker->find(id, &element) == false)
190 return nullptr;
191 return (const SkDisplayable*) element;
192 }
193
getElementType(const SkDisplayable * ae)194 SkElementType SkAnimator::getElementType(const SkDisplayable* ae) {
195 SkDisplayable* element = (SkDisplayable*) ae;
196 const SkMemberInfo* info = SkDisplayType::GetMembers(fMaker, element->getType(), nullptr);
197 return (SkElementType) SkDisplayType::Find(fMaker, info);
198 }
199
getElementType(const char * id)200 SkElementType SkAnimator::getElementType(const char* id) {
201 const SkDisplayable* element = getElement(id);
202 return getElementType(element);
203 }
204
getField(const SkDisplayable * ae,const char * field)205 const SkMemberInfo* SkAnimator::getField(const SkDisplayable* ae, const char* field) {
206 SkDisplayable* element = (SkDisplayable*) ae;
207 const SkMemberInfo* info = element->getMember(field);
208 return (const SkMemberInfo*) info;
209 }
210
getField(const char * elementID,const char * field)211 const SkMemberInfo* SkAnimator::getField(const char* elementID, const char* field) {
212 const SkDisplayable* element = getElement(elementID);
213 return getField(element, field);
214 }
215
getFieldType(const SkMemberInfo * ai)216 SkFieldType SkAnimator::getFieldType(const SkMemberInfo* ai) {
217 const SkMemberInfo* info = (const SkMemberInfo*) ai;
218 return (SkFieldType) info->getType();
219 }
220
getFieldType(const char * id,const char * fieldID)221 SkFieldType SkAnimator::getFieldType(const char* id, const char* fieldID) {
222 const SkMemberInfo* field = getField(id, fieldID);
223 return getFieldType(field);
224 }
225
getArrayCommon(const SkDisplayable * ae,const SkMemberInfo * ai,int index,SkOperand * operand)226 static bool getArrayCommon(const SkDisplayable* ae, const SkMemberInfo* ai,
227 int index, SkOperand* operand) {
228 const SkDisplayable* element = (const SkDisplayable*) ae;
229 const SkMemberInfo* info = (const SkMemberInfo*) ai;
230 SkASSERT(info->fType == SkType_Array);
231 return info->getArrayValue(element, index, operand);
232 }
233
getArrayInt(const SkDisplayable * ae,const SkMemberInfo * ai,int index)234 int32_t SkAnimator::getArrayInt(const SkDisplayable* ae,
235 const SkMemberInfo* ai, int index) {
236 SkOperand operand;
237 bool result = getArrayCommon(ae, ai, index, &operand);
238 return result ? operand.fS32 : SK_NaN32;
239 }
240
getArrayInt(const char * id,const char * fieldID,int index)241 int32_t SkAnimator::getArrayInt(const char* id, const char* fieldID, int index) {
242 const SkDisplayable* element = getElement(id);
243 if (element == nullptr)
244 return SK_NaN32;
245 const SkMemberInfo* field = getField(element, fieldID);
246 if (field == nullptr)
247 return SK_NaN32;
248 return getArrayInt(element, field, index);
249 }
250
getArrayScalar(const SkDisplayable * ae,const SkMemberInfo * ai,int index)251 SkScalar SkAnimator::getArrayScalar(const SkDisplayable* ae,
252 const SkMemberInfo* ai, int index) {
253 SkOperand operand;
254 bool result = getArrayCommon(ae, ai, index, &operand);
255 return result ? operand.fScalar : SK_ScalarNaN;
256 }
257
getArrayScalar(const char * id,const char * fieldID,int index)258 SkScalar SkAnimator::getArrayScalar(const char* id, const char* fieldID, int index) {
259 const SkDisplayable* element = getElement(id);
260 if (element == nullptr)
261 return SK_ScalarNaN;
262 const SkMemberInfo* field = getField(element, fieldID);
263 if (field == nullptr)
264 return SK_ScalarNaN;
265 return getArrayScalar(element, field, index);
266 }
267
getArrayString(const SkDisplayable * ae,const SkMemberInfo * ai,int index)268 const char* SkAnimator::getArrayString(const SkDisplayable* ae,
269 const SkMemberInfo* ai, int index) {
270 SkOperand operand;
271 bool result = getArrayCommon(ae, ai, index, &operand);
272 return result ? operand.fString->c_str() : nullptr;
273 }
274
getArrayString(const char * id,const char * fieldID,int index)275 const char* SkAnimator::getArrayString(const char* id, const char* fieldID, int index) {
276 const SkDisplayable* element = getElement(id);
277 if (element == nullptr)
278 return nullptr;
279 const SkMemberInfo* field = getField(element, fieldID);
280 if (field == nullptr)
281 return nullptr;
282 return getArrayString(element, field, index);
283 }
284
getInterval()285 SkMSec SkAnimator::getInterval() {
286 return fMaker->fMinimumInterval == (SkMSec) -1 ? 0 : fMaker->fMinimumInterval;
287 }
288
getInvalBounds(SkRect * inval)289 void SkAnimator::getInvalBounds(SkRect* inval) {
290 if (fMaker->fDisplayList.fHasUnion) {
291 inval->fLeft = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fLeft);
292 inval->fTop = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fTop);
293 inval->fRight = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fRight);
294 inval->fBottom = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fBottom);
295 } else {
296 inval->fLeft = inval->fTop = -SK_ScalarMax;
297 inval->fRight = inval->fBottom = SK_ScalarMax;
298 }
299 }
300
getParserError()301 const SkXMLParserError* SkAnimator::getParserError() {
302 return &fMaker->fError;
303 }
304
getParserErrorString()305 const char* SkAnimator::getParserErrorString() {
306 if (fMaker->fErrorString.size() == 0 && fMaker->fError.hasError())
307 fMaker->setErrorString();
308 return fMaker->fErrorString.c_str();
309 }
310
getInt(const SkDisplayable * element,const SkMemberInfo * info)311 int32_t SkAnimator::getInt(const SkDisplayable* element, const SkMemberInfo* info) {
312 if (info->fType != SkType_MemberProperty) {
313 SkOperand operand;
314 if (info->getType() == SkType_Int) {
315 info->getValue(element, &operand, 1);
316 return operand.fS32;
317 }
318 return SK_NaN32;
319 }
320 SkScriptValue scriptValue;
321 bool success = element->getProperty(info->propertyIndex(), &scriptValue);
322 if (success && scriptValue.fType == SkType_Int)
323 return scriptValue.fOperand.fS32;
324 return SK_NaN32;
325 }
326
getInt(const char * id,const char * fieldID)327 int32_t SkAnimator::getInt(const char* id, const char* fieldID) {
328 const SkDisplayable* element = getElement(id);
329 if (element == nullptr)
330 return SK_NaN32;
331 const SkMemberInfo* field = getField(element, fieldID);
332 if (field == nullptr)
333 return SK_NaN32;
334 return getInt(element, field);
335 }
336
getScalar(const SkDisplayable * element,const SkMemberInfo * info)337 SkScalar SkAnimator::getScalar(const SkDisplayable* element, const SkMemberInfo* info) {
338 if (info->fType != SkType_MemberProperty) {
339 SkOperand operand;
340 if (info->getType() == SkType_Float) {
341 info->getValue(element, &operand, 1);
342 return operand.fScalar;
343 }
344 return SK_ScalarNaN;
345 }
346 SkScriptValue scriptValue;
347 bool success = element->getProperty(info->propertyIndex(), &scriptValue);
348 if (success && scriptValue.fType == SkType_Float)
349 return scriptValue.fOperand.fScalar;
350 return SK_ScalarNaN;
351 }
352
getScalar(const char * id,const char * fieldID)353 SkScalar SkAnimator::getScalar(const char* id, const char* fieldID) {
354 const SkDisplayable* element = getElement(id);
355 if (element == nullptr)
356 return SK_ScalarNaN;
357 const SkMemberInfo* field = getField(element, fieldID);
358 if (field == nullptr)
359 return SK_ScalarNaN;
360 return getScalar(element, field);
361 }
362
getString(const SkDisplayable * ae,const SkMemberInfo * ai)363 const char* SkAnimator::getString(const SkDisplayable* ae,
364 const SkMemberInfo* ai) {
365 const SkDisplayable* element = (const SkDisplayable*) ae;
366 const SkMemberInfo* info = (const SkMemberInfo*) ai;
367 SkString* temp;
368 info->getString(element, &temp);
369 return temp->c_str();
370 }
371
getString(const char * id,const char * fieldID)372 const char* SkAnimator::getString(const char* id, const char* fieldID) {
373 const SkDisplayable* element = getElement(id);
374 if (element == nullptr)
375 return nullptr;
376 const SkMemberInfo* field = getField(element, fieldID);
377 if (field == nullptr)
378 return nullptr;
379 return getString(element, field);
380 }
381
getURIBase()382 const char* SkAnimator::getURIBase() {
383 return fMaker->fPrefix.c_str();
384 }
385
initialize()386 void SkAnimator::initialize() {
387 delete fMaker;
388 fMaker = new SkAnimateMaker(this, nullptr, nullptr);
389 decodeMemory(gMathPrimer, sizeof(gMathPrimer)-1);
390 #ifdef SK_BUILD_FOR_ANDROID
391 InitializeSkExtraPathEffects(this);
392 #endif
393 }
394
395
396 #ifdef SK_DEBUG
isTrackingEvents()397 bool SkAnimator::isTrackingEvents() {
398 return false;
399 }
400 #endif
401
onEvent(const SkEvent & evt)402 bool SkAnimator::onEvent(const SkEvent& evt) {
403 #ifdef SK_DEBUG
404 SkAnimator* root = fMaker->getRoot();
405 if (root == nullptr)
406 root = this;
407 if (root->isTrackingEvents())
408 root->eventDone(evt);
409 #endif
410 if (evt.isType(SK_EventType_OnEnd)) {
411 SkEventState eventState;
412 SkDEBUGCODE(bool success =) evt.findPtr("anim", (void**) &eventState.fDisplayable);
413 SkASSERT(success);
414 SkDEBUGCODE(success =) evt.findS32("time", (int32_t*) &fMaker->fEnableTime);
415 SkASSERT(success);
416 fMaker->fAdjustedStart = fMaker->getAppTime() - fMaker->fEnableTime;
417 fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kOnEnd, &eventState);
418 fMaker->fAdjustedStart = 0;
419 goto inval;
420 }
421 if (evt.isType(SK_EventType_Delay)) {
422 fMaker->doDelayedEvent();
423 goto inval;
424 }
425 {
426 const char* id = evt.findString("id");
427 if (id == nullptr)
428 return false;
429 SkDisplayable** firstMovie = fMaker->fMovies.begin();
430 SkDisplayable** endMovie = fMaker->fMovies.end();
431 for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) {
432 SkDisplayMovie* movie = (SkDisplayMovie*) *ptr;
433 movie->doEvent(evt);
434 }
435 {
436 SkDisplayable* event;
437 if (fMaker->find(id, &event) == false)
438 return false;
439 #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
440 SkString debugOut;
441 SkMSec realTime = fMaker->getAppTime();
442 debugOut.appendS32(realTime - fMaker->fDebugTimeBase);
443 debugOut.append(" onEvent id=");
444 debugOut.append(id);
445 #endif
446 SkMSec time = evt.getFast32();
447 if (time != 0) {
448 SkMSec app = fMaker->getAppTime();
449 fMaker->setEnableTime(app, time);
450 #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
451 debugOut.append(" time=");
452 debugOut.appendS32(time - fMaker->fDebugTimeBase);
453 debugOut.append(" adjust=");
454 debugOut.appendS32(fMaker->fAdjustedStart);
455 #endif
456 }
457 #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
458 SkDebugf("%s\n", debugOut.c_str());
459 #endif
460 SkASSERT(event->isEvent());
461 SkDisplayEvent* displayEvent = (SkDisplayEvent*) event;
462 displayEvent->populateInput(*fMaker, evt);
463 displayEvent->enableEvent(*fMaker);
464 }
465 }
466 inval:
467 fMaker->notifyInval();
468 return true;
469 }
470
onEventPost(SkEvent * evt,SkEventSinkID sinkID)471 void SkAnimator::onEventPost(SkEvent* evt, SkEventSinkID sinkID)
472 {
473 #ifdef SK_DEBUG
474 SkAnimator* root = fMaker->getRoot();
475 if (root) {
476 root->onEventPost(evt, sinkID);
477 return;
478 }
479 #else
480 SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
481 #endif
482 evt->setTargetID(sinkID)->post();
483 }
484
onEventPostTime(SkEvent * evt,SkEventSinkID sinkID,SkMSec time)485 void SkAnimator::onEventPostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time)
486 {
487 #ifdef SK_DEBUG
488 SkAnimator* root = fMaker->getRoot();
489 if (root) {
490 root->onEventPostTime(evt, sinkID, time);
491 return;
492 }
493 #else
494 SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
495 #endif
496 evt->setTargetID(sinkID)->postTime(time);
497 }
498
reset()499 void SkAnimator::reset() {
500 fMaker->fDisplayList.reset();
501 }
502
getHostEventSinkID() const503 SkEventSinkID SkAnimator::getHostEventSinkID() const {
504 return fMaker->fHostEventSinkID;
505 }
506
setHostEventSinkID(SkEventSinkID target)507 void SkAnimator::setHostEventSinkID(SkEventSinkID target) {
508 fMaker->fHostEventSinkID = target;
509 }
510
onSetHostHandler(Handler)511 void SkAnimator::onSetHostHandler(Handler ) {
512 }
513
setJavaOwner(Handler)514 void SkAnimator::setJavaOwner(Handler ) {
515 }
516
setArrayString(const char * id,const char * fieldID,const char ** array,int num)517 bool SkAnimator::setArrayString(const char* id, const char* fieldID, const char** array, int num)
518 {
519 SkTypedArray tArray(SkType_String);
520 tArray.setCount(num);
521 for (int i = 0; i < num; i++) {
522 SkOperand op;
523 op.fString = new SkString(array[i]);
524 tArray[i] = op;
525 }
526 return setArray(id, fieldID, tArray);
527 }
setArrayInt(const char * id,const char * fieldID,const int * array,int num)528 bool SkAnimator::setArrayInt(const char* id, const char* fieldID, const int* array, int num)
529 {
530 SkTypedArray tArray(SkType_Int);
531 tArray.setCount(num);
532 for (int i = 0; i < num; i++) {
533 SkOperand op;
534 op.fS32 = array[i];
535 tArray[i] = op;
536 }
537 return setArray(id, fieldID, tArray);
538 }
539
setArray(SkDisplayable * element,const SkMemberInfo * info,SkTypedArray array)540 bool SkAnimator::setArray(SkDisplayable* element, const SkMemberInfo* info, SkTypedArray array) {
541 if (info->fType != SkType_Array)
542 return false; //the field is not an array
543 //i think we can handle the case where the displayable itself is an array differently from the
544 //case where it has an array - for one thing, if it is an array, i think we can change its type
545 //if it's not, we cannot
546 SkDisplayTypes type = element->getType();
547 if (type == SkType_Array) {
548 SkDisplayArray* dispArray = (SkDisplayArray*) element;
549 dispArray->values = array;
550 return true;
551 }
552 else
553 return false; //currently i don't care about this case
554 }
555
setArray(const char * id,const char * fieldID,SkTypedArray array)556 bool SkAnimator::setArray(const char* id, const char* fieldID, SkTypedArray array) {
557 SkDisplayable* element = (SkDisplayable*) getElement(id);
558 //should I go ahead and change all 'nullptr's to 'nullptr'?
559 if (element == nullptr)
560 return false;
561 const SkMemberInfo* field = getField(element, fieldID);
562 if (field == nullptr)
563 return false;
564 return setArray(element, field, array);
565 }
566
setInt(SkDisplayable * element,const SkMemberInfo * info,int32_t s32)567 bool SkAnimator::setInt(SkDisplayable* element, const SkMemberInfo* info, int32_t s32) {
568 if (info->fType != SkType_MemberProperty) {
569 SkOperand operand;
570 operand.fS32 = s32;
571 SkASSERT(info->getType() == SkType_Int);
572 info->setValue(element, &operand, 1);
573 } else {
574 SkScriptValue scriptValue;
575 scriptValue.fType = SkType_Int;
576 scriptValue.fOperand.fS32 = s32;
577 element->setProperty(info->propertyIndex(), scriptValue);
578 }
579 return true;
580 }
581
setInt(const char * id,const char * fieldID,int32_t s32)582 bool SkAnimator::setInt(const char* id, const char* fieldID, int32_t s32) {
583 SkDisplayable* element = (SkDisplayable*) getElement(id);
584 if (element == nullptr)
585 return false;
586 const SkMemberInfo* field = getField(element, fieldID);
587 if (field == nullptr)
588 return false;
589 return setInt(element, field, s32);
590 }
591
setScalar(SkDisplayable * element,const SkMemberInfo * info,SkScalar scalar)592 bool SkAnimator::setScalar(SkDisplayable* element, const SkMemberInfo* info, SkScalar scalar) {
593 if (info->fType != SkType_MemberProperty) {
594 SkOperand operand;
595 operand.fScalar = scalar;
596 SkASSERT(info->getType() == SkType_Float);
597 info->setValue(element, &operand, 1);
598 } else {
599 SkScriptValue scriptValue;
600 scriptValue.fType = SkType_Float;
601 scriptValue.fOperand.fScalar = scalar;
602 element->setProperty(info->propertyIndex(), scriptValue);
603 }
604 return true;
605 }
606
setScalar(const char * id,const char * fieldID,SkScalar scalar)607 bool SkAnimator::setScalar(const char* id, const char* fieldID, SkScalar scalar) {
608 SkDisplayable* element = (SkDisplayable*) getElement(id);
609 if (element == nullptr)
610 return false;
611 const SkMemberInfo* field = getField(element, fieldID);
612 if (field == nullptr)
613 return false;
614 return setScalar(element, field, scalar);
615 }
616
setString(SkDisplayable * element,const SkMemberInfo * info,const char * str)617 bool SkAnimator::setString(SkDisplayable* element,
618 const SkMemberInfo* info, const char* str) {
619 // !!! until this is fixed, can't call script with global references from here
620 info->setValue(*fMaker, nullptr, 0, info->fCount, element, info->getType(), str, strlen(str));
621 return true;
622 }
623
setString(const char * id,const char * fieldID,const char * str)624 bool SkAnimator::setString(const char* id, const char* fieldID, const char* str) {
625 SkDisplayable* element = (SkDisplayable*) getElement(id);
626 if (element == nullptr)
627 return false;
628 const SkMemberInfo* field = getField(element, fieldID);
629 if (field == nullptr)
630 return false;
631 return setString(element, field, str);
632 }
633
setTimeline(const Timeline & timeline)634 void SkAnimator::setTimeline(const Timeline& timeline) {
635 fMaker->fTimeline = &timeline;
636 }
637
setURIBase(const char * uri)638 void SkAnimator::setURIBase(const char* uri) {
639 if (uri)
640 {
641 const char* tail = strrchr(uri, '/');
642 if (tail) {
643 SkString prefix(uri, tail - uri + 1);
644 if (uri[0] != '.' /*SkStream::IsAbsoluteURI(uri)*/)
645 fMaker->fPrefix.reset();
646 fMaker->fPrefix.append(prefix);
647 fMaker->fFileName.set(tail + 1);
648 } else
649 fMaker->fFileName.set(uri);
650 }
651 }
652
653 #ifdef SK_DEBUG
NoLeaks()654 bool SkAnimator::NoLeaks() {
655 #ifdef SK_BUILD_FOR_MAC
656 if (SkDisplayable::fAllocations.count() == 0)
657 return true;
658 // return SkDisplayable::fAllocationCount == 0;
659 SkDebugf("!!! leaked %d displayables:\n", SkDisplayable::fAllocations.count());
660 for (SkDisplayable** leak = SkDisplayable::fAllocations.begin(); leak < SkDisplayable::fAllocations.end(); leak++)
661 SkDebugf("%08x %s\n", *leak, (*leak)->id);
662 #endif
663 return false;
664 }
665 #endif
666
667 #ifdef SK_SUPPORT_UNITTEST
668 #include "SkAnimatorScript.h"
669 #include "SkBase64.h"
670 #include "SkParse.h"
671 #include "SkMemberInfo.h"
672
673 #define unittestline(type) { #type , type::UnitTest }
674 #endif
675
676
677 #ifdef SK_SUPPORT_UNITTEST
Init(bool runUnitTests)678 void SkAnimator::Init(bool runUnitTests) {
679 if (runUnitTests == false)
680 return;
681 static const struct {
682 const char* fTypeName;
683 void (*fUnitTest)( );
684 } gUnitTests[] = {
685 unittestline(SkBase64),
686 unittestline(SkDisplayType),
687 unittestline(SkParse),
688 unittestline(SkScriptEngine),
689 // unittestline(SkScriptEngine2), // compiled script experiment
690 unittestline(SkAnimatorScript)
691 };
692 for (int i = 0; i < (int)SK_ARRAY_COUNT(gUnitTests); i++)
693 {
694 SkDebugf("SkAnimator: Running UnitTest for %s\n", gUnitTests[i].fTypeName);
695 gUnitTests[i].fUnitTest();
696 SkDebugf("SkAnimator: End UnitTest for %s\n", gUnitTests[i].fTypeName);
697 }
698 }
699 #else
Init(bool)700 void SkAnimator::Init(bool) {}
701 #endif
702
Term()703 void SkAnimator::Term() {
704 }
705