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