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 45 SkAnimator::SkAnimator() : fMaker(NULL) { 46 initialize(); 47 } 48 49 SkAnimator::~SkAnimator() { 50 SkDELETE(fMaker); 51 } 52 53 void SkAnimator::addExtras(SkExtras* extras) { 54 *fMaker->fExtras.append() = extras; 55 } 56 57 bool SkAnimator::appendStream(SkStream* stream) { 58 return decodeStream(stream); 59 } 60 61 bool SkAnimator::decodeMemory(const void* buffer, size_t size) 62 { 63 fMaker->fFileName.reset(); 64 SkDisplayXMLParser parser(*fMaker); 65 return parser.parse((const char*)buffer, size); 66 } 67 68 bool SkAnimator::decodeStream(SkStream* stream) 69 { 70 SkDisplayXMLParser parser(*fMaker); 71 bool result = parser.parse(*stream); 72 fMaker->setErrorString(); 73 return result; 74 } 75 76 bool SkAnimator::decodeDOM(const SkDOM& dom, const SkDOMNode* node) 77 { 78 fMaker->fFileName.reset(); 79 SkDisplayXMLParser parser(*fMaker); 80 return parser.parse(dom, node); 81 } 82 83 bool SkAnimator::decodeURI(const char uri[]) { 84 // SkDebugf("animator decode %s\n", uri); 85 86 // SkStream* stream = SkStream::GetURIStream(fMaker->fPrefix.c_str(), uri); 87 SkStream* stream = new SkFILEStream(uri); 88 89 SkAutoTDelete<SkStream> autoDel(stream); 90 setURIBase(uri); 91 return decodeStream(stream); 92 } 93 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 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 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 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 141 bool SkAnimator::doUserEvent(const SkEvent& evt) { 142 fMaker->fEnableTime = fMaker->getAppTime(); 143 return onEvent(evt); 144 } 145 146 SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkPaint* paint, SkMSec time) { 147 if (paint == NULL) 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 159 SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkMSec time) { 160 SkPaint paint; 161 return draw(canvas, &paint, time); 162 } 163 164 #ifdef SK_DEBUG 165 void SkAnimator::eventDone(const SkEvent& ) { 166 } 167 #endif 168 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 180 const SkAnimator* SkAnimator::getAnimator(const SkDisplayable* displayable) const { 181 if (displayable->getType() != SkType_Movie) 182 return NULL; 183 const SkDisplayMovie* movie = (const SkDisplayMovie*) displayable; 184 return movie->getAnimator(); 185 } 186 187 const SkDisplayable* SkAnimator::getElement(const char* id) { 188 SkDisplayable* element; 189 if (fMaker->find(id, &element) == false) 190 return NULL; 191 return (const SkDisplayable*) element; 192 } 193 194 SkElementType SkAnimator::getElementType(const SkDisplayable* ae) { 195 SkDisplayable* element = (SkDisplayable*) ae; 196 const SkMemberInfo* info = SkDisplayType::GetMembers(fMaker, element->getType(), NULL); 197 return (SkElementType) SkDisplayType::Find(fMaker, info); 198 } 199 200 SkElementType SkAnimator::getElementType(const char* id) { 201 const SkDisplayable* element = getElement(id); 202 return getElementType(element); 203 } 204 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 211 const SkMemberInfo* SkAnimator::getField(const char* elementID, const char* field) { 212 const SkDisplayable* element = getElement(elementID); 213 return getField(element, field); 214 } 215 216 SkFieldType SkAnimator::getFieldType(const SkMemberInfo* ai) { 217 const SkMemberInfo* info = (const SkMemberInfo*) ai; 218 return (SkFieldType) info->getType(); 219 } 220 221 SkFieldType SkAnimator::getFieldType(const char* id, const char* fieldID) { 222 const SkMemberInfo* field = getField(id, fieldID); 223 return getFieldType(field); 224 } 225 226 static bool getArrayCommon(const SkDisplayable* ae, const SkMemberInfo* ai, 227 int index, SkOperand* operand, SkDisplayTypes type) { 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 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, SkType_Int); 238 return result ? operand.fS32 : SK_NaN32; 239 } 240 241 int32_t SkAnimator::getArrayInt(const char* id, const char* fieldID, int index) { 242 const SkDisplayable* element = getElement(id); 243 if (element == NULL) 244 return SK_NaN32; 245 const SkMemberInfo* field = getField(element, fieldID); 246 if (field == NULL) 247 return SK_NaN32; 248 return getArrayInt(element, field, index); 249 } 250 251 SkScalar SkAnimator::getArrayScalar(const SkDisplayable* ae, 252 const SkMemberInfo* ai, int index) { 253 SkOperand operand; 254 bool result = getArrayCommon(ae, ai, index, &operand, SkType_Float); 255 return result ? operand.fScalar : SK_ScalarNaN; 256 } 257 258 SkScalar SkAnimator::getArrayScalar(const char* id, const char* fieldID, int index) { 259 const SkDisplayable* element = getElement(id); 260 if (element == NULL) 261 return SK_ScalarNaN; 262 const SkMemberInfo* field = getField(element, fieldID); 263 if (field == NULL) 264 return SK_ScalarNaN; 265 return getArrayScalar(element, field, index); 266 } 267 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, SkType_String); 272 return result ? operand.fString->c_str() : NULL; 273 } 274 275 const char* SkAnimator::getArrayString(const char* id, const char* fieldID, int index) { 276 const SkDisplayable* element = getElement(id); 277 if (element == NULL) 278 return NULL; 279 const SkMemberInfo* field = getField(element, fieldID); 280 if (field == NULL) 281 return NULL; 282 return getArrayString(element, field, index); 283 } 284 285 SkMSec SkAnimator::getInterval() { 286 return fMaker->fMinimumInterval == (SkMSec) -1 ? 0 : fMaker->fMinimumInterval; 287 } 288 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 301 const SkXMLParserError* SkAnimator::getParserError() { 302 return &fMaker->fError; 303 } 304 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 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 327 int32_t SkAnimator::getInt(const char* id, const char* fieldID) { 328 const SkDisplayable* element = getElement(id); 329 if (element == NULL) 330 return SK_NaN32; 331 const SkMemberInfo* field = getField(element, fieldID); 332 if (field == NULL) 333 return SK_NaN32; 334 return getInt(element, field); 335 } 336 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 353 SkScalar SkAnimator::getScalar(const char* id, const char* fieldID) { 354 const SkDisplayable* element = getElement(id); 355 if (element == NULL) 356 return SK_ScalarNaN; 357 const SkMemberInfo* field = getField(element, fieldID); 358 if (field == NULL) 359 return SK_ScalarNaN; 360 return getScalar(element, field); 361 } 362 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 372 const char* SkAnimator::getString(const char* id, const char* fieldID) { 373 const SkDisplayable* element = getElement(id); 374 if (element == NULL) 375 return NULL; 376 const SkMemberInfo* field = getField(element, fieldID); 377 if (field == NULL) 378 return NULL; 379 return getString(element, field); 380 } 381 382 const char* SkAnimator::getURIBase() { 383 return fMaker->fPrefix.c_str(); 384 } 385 386 void SkAnimator::initialize() { 387 SkDELETE(fMaker); 388 fMaker = SkNEW_ARGS(SkAnimateMaker, (this, NULL, NULL)); 389 decodeMemory(gMathPrimer, sizeof(gMathPrimer)-1); 390 #ifdef SK_BUILD_FOR_ANDROID 391 InitializeSkExtraPathEffects(this); 392 #endif 393 } 394 395 396 #ifdef SK_DEBUG 397 bool SkAnimator::isTrackingEvents() { 398 return false; 399 } 400 #endif 401 402 bool SkAnimator::onEvent(const SkEvent& evt) { 403 #ifdef SK_DEBUG 404 SkAnimator* root = fMaker->getRoot(); 405 if (root == NULL) 406 root = this; 407 if (root->isTrackingEvents()) 408 root->eventDone(evt); 409 #endif 410 if (evt.isType(SK_EventType_OnEnd)) { 411 SkEventState eventState; 412 bool success = evt.findPtr("anim", (void**) &eventState.fDisplayable); 413 SkASSERT(success); 414 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 == NULL) 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 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 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 499 void SkAnimator::reset() { 500 fMaker->fDisplayList.reset(); 501 } 502 503 SkEventSinkID SkAnimator::getHostEventSinkID() const { 504 return fMaker->fHostEventSinkID; 505 } 506 507 void SkAnimator::setHostEventSinkID(SkEventSinkID target) { 508 fMaker->fHostEventSinkID = target; 509 } 510 511 void SkAnimator::onSetHostHandler(Handler ) { 512 } 513 514 void SkAnimator::setJavaOwner(Handler ) { 515 } 516 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 } 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 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 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 'NULL's to 'NULL'? 559 if (element == NULL) 560 return false; 561 const SkMemberInfo* field = getField(element, fieldID); 562 if (field == NULL) 563 return false; 564 return setArray(element, field, array); 565 } 566 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 582 bool SkAnimator::setInt(const char* id, const char* fieldID, int32_t s32) { 583 SkDisplayable* element = (SkDisplayable*) getElement(id); 584 if (element == NULL) 585 return false; 586 const SkMemberInfo* field = getField(element, fieldID); 587 if (field == NULL) 588 return false; 589 return setInt(element, field, s32); 590 } 591 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 607 bool SkAnimator::setScalar(const char* id, const char* fieldID, SkScalar scalar) { 608 SkDisplayable* element = (SkDisplayable*) getElement(id); 609 if (element == NULL) 610 return false; 611 const SkMemberInfo* field = getField(element, fieldID); 612 if (field == NULL) 613 return false; 614 return setScalar(element, field, scalar); 615 } 616 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, NULL, 0, info->fCount, element, info->getType(), str, strlen(str)); 621 return true; 622 } 623 624 bool SkAnimator::setString(const char* id, const char* fieldID, const char* str) { 625 SkDisplayable* element = (SkDisplayable*) getElement(id); 626 if (element == NULL) 627 return false; 628 const SkMemberInfo* field = getField(element, fieldID); 629 if (field == NULL) 630 return false; 631 return setString(element, field, str); 632 } 633 634 void SkAnimator::setTimeline(const Timeline& timeline) { 635 fMaker->fTimeline = &timeline; 636 } 637 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 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 void SkAnimator::Init(bool runUnitTests) { 678 #ifdef SK_SUPPORT_UNITTEST 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 #endif 699 } 700 701 void SkAnimator::Term() { 702 } 703 704 705 706