|  | 
 | /* | 
 |  * Copyright 2006 The Android Open Source Project | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 |  | 
 | #include "SkDrawGroup.h" | 
 | #include "SkAnimateMaker.h" | 
 | #include "SkAnimatorScript.h" | 
 | #include "SkCanvas.h" | 
 | #include "SkDisplayApply.h" | 
 | #include "SkPaint.h" | 
 | #ifdef SK_DEBUG | 
 | #include "SkDisplayList.h" | 
 | #endif | 
 |  | 
 | #if SK_USE_CONDENSED_INFO == 0 | 
 |  | 
 | const SkMemberInfo SkGroup::fInfo[] = { | 
 |     SK_MEMBER(condition, String), | 
 |     SK_MEMBER(enableCondition, String) | 
 | }; | 
 |  | 
 | #endif | 
 |  | 
 | DEFINE_GET_MEMBER(SkGroup); | 
 |  | 
 | SkGroup::SkGroup() : fParentList(NULL), fOriginal(NULL) { | 
 | } | 
 |  | 
 | SkGroup::~SkGroup() { | 
 |     if (fOriginal)  // has been copied | 
 |         return; | 
 |     int index = 0; | 
 |     int max = fCopies.count() << 5; | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         if (index >= max || markedForDelete(index)) | 
 |             delete *ptr; | 
 | //      else { | 
 | //          SkApply* apply = (SkApply*) *ptr; | 
 | //          SkASSERT(apply->isApply()); | 
 | //          SkASSERT(apply->getScope()); | 
 | //          delete apply->getScope(); | 
 | //      } | 
 |         index++; | 
 |     } | 
 | } | 
 |  | 
 | bool SkGroup::add(SkAnimateMaker& , SkDisplayable* child) { | 
 |     SkASSERT(child);  | 
 | //  SkASSERT(child->isDrawable()); | 
 |     *fChildren.append() = (SkDrawable*) child; | 
 |     if (child->isGroup()) { | 
 |         SkGroup* groupie = (SkGroup*) child; | 
 |         SkASSERT(groupie->fParentList == NULL); | 
 |         groupie->fParentList = &fChildren; | 
 |     } | 
 |     return true; | 
 | } | 
 |  | 
 | bool SkGroup::contains(SkDisplayable* match) { | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         SkDrawable* drawable = *ptr; | 
 |         if (drawable == match || drawable->contains(match)) | 
 |             return true; | 
 |     } | 
 |     return false; | 
 | } | 
 |  | 
 | SkGroup* SkGroup::copy() { | 
 |     SkGroup* result = new SkGroup(); | 
 |     result->fOriginal = this; | 
 |     result->fChildren = fChildren; | 
 |     return result; | 
 | } | 
 |  | 
 | SkBool SkGroup::copySet(int index) { | 
 |     return (fCopies[index >> 5] & 1 << (index & 0x1f)) != 0; | 
 | } | 
 |  | 
 | SkDisplayable* SkGroup::deepCopy(SkAnimateMaker* maker) { | 
 |     SkDisplayable* copy = INHERITED::deepCopy(maker); | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         SkDisplayable* displayable = (SkDisplayable*)*ptr; | 
 |         SkDisplayable* deeperCopy = displayable->deepCopy(maker); | 
 |         ((SkGroup*)copy)->add(*maker, deeperCopy); | 
 |     } | 
 |     return copy; | 
 | } | 
 |  | 
 | bool SkGroup::doEvent(SkDisplayEvent::Kind kind, SkEventState* state) { | 
 |     bool handled = false; | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         SkDrawable* drawable = *ptr; | 
 |         if (drawable->isDrawable() == false) | 
 |             continue; | 
 |         handled |= drawable->doEvent(kind, state); | 
 |     } | 
 |     return handled; | 
 | } | 
 |  | 
 | bool SkGroup::draw(SkAnimateMaker& maker) { | 
 |     bool conditionTrue = ifCondition(maker, this, condition); | 
 |     bool result = false; | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         SkDrawable* drawable = *ptr; | 
 |         if (drawable->isDrawable() == false) | 
 |             continue; | 
 |         if (conditionTrue == false) { | 
 |             if (drawable->isApply()) | 
 |                 ((SkApply*) drawable)->disable(); | 
 |             continue; | 
 |         } | 
 |         maker.validate(); | 
 |         result |= drawable->draw(maker); | 
 |         maker.validate(); | 
 |     } | 
 |     return result; | 
 | } | 
 |  | 
 | #ifdef SK_DUMP_ENABLED | 
 | void SkGroup::dump(SkAnimateMaker* maker) { | 
 |     dumpBase(maker); | 
 |     if (condition.size() > 0) | 
 |         SkDebugf("condition=\"%s\" ", condition.c_str()); | 
 |     if (enableCondition.size() > 0) | 
 |         SkDebugf("enableCondition=\"%s\" ", enableCondition.c_str()); | 
 |     dumpDrawables(maker); | 
 | } | 
 |  | 
 | void SkGroup::dumpDrawables(SkAnimateMaker* maker) { | 
 |     SkDisplayList::fIndent += 4; | 
 |     int save = SkDisplayList::fDumpIndex; | 
 |     SkDisplayList::fDumpIndex = 0; | 
 |     bool closedYet = false; | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         if (closedYet == false) { | 
 |             closedYet = true; | 
 |             SkDebugf(">\n"); | 
 |         } | 
 |         SkDrawable* drawable = *ptr; | 
 |         drawable->dump(maker); | 
 |         SkDisplayList::fDumpIndex++; | 
 |     } | 
 |     SkDisplayList::fIndent -= 4; | 
 |     SkDisplayList::fDumpIndex = save; | 
 |     if (closedYet) //we had children, now it's time to close the group | 
 |         dumpEnd(maker); | 
 |     else    //no children | 
 |         SkDebugf("/>\n"); | 
 | } | 
 |  | 
 | void SkGroup::dumpEvents() { | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         SkDrawable* drawable = *ptr; | 
 |         drawable->dumpEvents(); | 
 |     } | 
 | } | 
 | #endif | 
 |  | 
 | bool SkGroup::enable(SkAnimateMaker& maker ) { | 
 |     reset(); | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         SkDrawable* drawable = *ptr; | 
 |         if (ifCondition(maker, drawable, enableCondition) == false) | 
 |             continue; | 
 |         drawable->enable(maker); | 
 |     } | 
 |     return true;    // skip add; already added so that scope is findable by children | 
 | } | 
 |  | 
 | int SkGroup::findGroup(SkDrawable* match,  SkTDDrawableArray** list, | 
 |                  SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList) { | 
 |     *list = &fChildren; | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         SkDrawable* drawable = *ptr; | 
 |         if (drawable->isGroup()) { | 
 |             SkGroup* childGroup = (SkGroup*) drawable; | 
 |             if (childGroup->fOriginal == match) | 
 |                 goto foundMatch; | 
 |         } | 
 |         if (drawable == match) { | 
 | foundMatch: | 
 |             *parent = this; | 
 |             return (int) (ptr - fChildren.begin()); | 
 |         } | 
 |     } | 
 |     *grandList = &fChildren; | 
 |     return SkDisplayList::SearchForMatch(match, list, parent, found, grandList); | 
 | } | 
 |  | 
 | bool SkGroup::hasEnable() const { | 
 |     return true; | 
 | } | 
 |  | 
 | bool SkGroup::ifCondition(SkAnimateMaker& maker, SkDrawable* drawable, | 
 |         SkString& conditionString) { | 
 |     if (conditionString.size() == 0) | 
 |         return true; | 
 |     int32_t result; | 
 |     bool success = SkAnimatorScript::EvaluateInt(maker, this, conditionString.c_str(), &result); | 
 | #ifdef SK_DUMP_ENABLED | 
 |     if (maker.fDumpGConditions) { | 
 |         SkDebugf("group: "); | 
 |         dumpBase(&maker); | 
 |         SkDebugf("condition=%s ", conditionString.c_str()); | 
 |         if (success == false) | 
 |             SkDebugf("(script failed)\n"); | 
 |         else | 
 |             SkDebugf("success=%s\n", result != 0 ? "true" : "false"); | 
 |     } | 
 | #endif | 
 |     return success && result != 0; | 
 | } | 
 |  | 
 | void SkGroup::initialize() { | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         SkDrawable* drawable = *ptr; | 
 |         if (drawable->isDrawable() == false) | 
 |             continue; | 
 |         drawable->initialize(); | 
 |     } | 
 | } | 
 |  | 
 | void SkGroup::markCopyClear(int index) { | 
 |     if (index < 0) | 
 |         index = fChildren.count(); | 
 |     fCopies[index >> 5] &= ~(1 << (index & 0x1f)); | 
 | } | 
 |  | 
 | void SkGroup::markCopySet(int index) { | 
 |     if (index < 0) | 
 |         index = fChildren.count(); | 
 |     fCopies[index >> 5] |= 1 << (index & 0x1f); | 
 | } | 
 |  | 
 | void SkGroup::markCopySize(int index) { | 
 |     if (index < 0) | 
 |         index = fChildren.count() + 1; | 
 |     int oldLongs = fCopies.count(); | 
 |     int newLongs = (index >> 5) + 1; | 
 |     if (oldLongs < newLongs) { | 
 |         fCopies.setCount(newLongs); | 
 |         memset(&fCopies[oldLongs], 0, (newLongs - oldLongs) << 2); | 
 |     } | 
 | } | 
 |  | 
 | void SkGroup::reset() { | 
 |     if (fOriginal)  // has been copied | 
 |         return; | 
 |     int index = 0; | 
 |     int max = fCopies.count() << 5; | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         if (index >= max || copySet(index) == false) | 
 |             continue; | 
 |         SkApply* apply = (SkApply*) *ptr; | 
 |         SkASSERT(apply->isApply()); | 
 |         SkASSERT(apply->getScope()); | 
 |         *ptr = apply->getScope(); | 
 |         markCopyClear(index); | 
 |         index++; | 
 |     } | 
 | } | 
 |  | 
 | bool SkGroup::resolveIDs(SkAnimateMaker& maker, SkDisplayable* orig, SkApply* apply) { | 
 |     SkGroup* original = (SkGroup*) orig; | 
 |     SkTDDrawableArray& originalChildren = original->fChildren; | 
 |     SkDrawable** originalPtr = originalChildren.begin(); | 
 |     SkDrawable** ptr = fChildren.begin(); | 
 |     SkDrawable** end = fChildren.end(); | 
 |     SkDrawable** origChild = ((SkGroup*) orig)->fChildren.begin(); | 
 |     while (ptr < end) { | 
 |         SkDrawable* drawable = *ptr++; | 
 |         maker.resolveID(drawable, *origChild++); | 
 |         if (drawable->resolveIDs(maker, *originalPtr++, apply) == true) | 
 |             return true; // failed | 
 |     } | 
 |     return false; | 
 | } | 
 |  | 
 | void SkGroup::setSteps(int steps) { | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         SkDrawable* drawable = *ptr; | 
 |         if (drawable->isDrawable() == false) | 
 |             continue; | 
 |         drawable->setSteps(steps); | 
 |     } | 
 | } | 
 |  | 
 | #ifdef SK_DEBUG | 
 | void SkGroup::validate() { | 
 |     for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { | 
 |         SkDrawable* drawable = *ptr; | 
 |         drawable->validate(); | 
 |     } | 
 | } | 
 | #endif | 
 |  | 
 | #if SK_USE_CONDENSED_INFO == 0 | 
 |  | 
 | const SkMemberInfo SkSave::fInfo[] = { | 
 |     SK_MEMBER_INHERITED | 
 | }; | 
 |  | 
 | #endif | 
 |  | 
 | DEFINE_GET_MEMBER(SkSave); | 
 |  | 
 | bool SkSave::draw(SkAnimateMaker& maker) { | 
 |     maker.fCanvas->save(); | 
 |     SkPaint* save = maker.fPaint; | 
 |     SkPaint local = SkPaint(*maker.fPaint); | 
 |     maker.fPaint = &local; | 
 |     bool result = INHERITED::draw(maker); | 
 |     maker.fPaint = save; | 
 |     maker.fCanvas->restore(); | 
 |     return result; | 
 | } | 
 |  | 
 |  |