/*
* 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(nullptr), fOriginal(nullptr) {
}
SkGroup::~SkGroup() {
if (fOriginal) // has been copied
return;
int index = 0;
int max = fCopies.count() << 5;
for (SkADrawable** 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::addChild(SkAnimateMaker& , SkDisplayable* child) {
SkASSERT(child);
// SkASSERT(child->isDrawable());
*fChildren.append() = (SkADrawable*) child;
if (child->isGroup()) {
SkGroup* groupie = (SkGroup*) child;
SkASSERT(groupie->fParentList == nullptr);
groupie->fParentList = &fChildren;
}
return true;
}
bool SkGroup::contains(SkDisplayable* match) {
for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
SkADrawable* 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 (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
SkDisplayable* displayable = (SkDisplayable*)*ptr;
SkDisplayable* deeperCopy = displayable->deepCopy(maker);
((SkGroup*)copy)->addChild(*maker, deeperCopy);
}
return copy;
}
bool SkGroup::doEvent(SkDisplayEvent::Kind kind, SkEventState* state) {
bool handled = false;
for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
SkADrawable* 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 (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
SkADrawable* 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 (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
if (closedYet == false) {
closedYet = true;
SkDebugf(">\n");
}
SkADrawable* 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 (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
SkADrawable* drawable = *ptr;
drawable->dumpEvents();
}
}
#endif
bool SkGroup::enable(SkAnimateMaker& maker ) {
reset();
for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
SkADrawable* 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(SkADrawable* match, SkTDDrawableArray** list,
SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList) {
*list = &fChildren;
for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
SkADrawable* 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, SkADrawable*,
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 (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
SkADrawable* 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 (SkADrawable** 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;
SkADrawable** originalPtr = originalChildren.begin();
SkADrawable** ptr = fChildren.begin();
SkADrawable** end = fChildren.end();
SkADrawable** origChild = ((SkGroup*) orig)->fChildren.begin();
while (ptr < end) {
SkADrawable* drawable = *ptr++;
maker.resolveID(drawable, *origChild++);
if (drawable->resolveIDs(maker, *originalPtr++, apply) == true)
return true; // failed
}
return false;
}
void SkGroup::setSteps(int steps) {
for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
SkADrawable* drawable = *ptr;
if (drawable->isDrawable() == false)
continue;
drawable->setSteps(steps);
}
}
#ifdef SK_DEBUG
void SkGroup::validate() {
for (SkADrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
SkADrawable* 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;
}