/*
* 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 "SkDisplayAdd.h"
#include "SkAnimateMaker.h"
#include "SkDisplayApply.h"
#include "SkDisplayList.h"
#include "SkADrawable.h"
#include "SkDrawGroup.h"
#if SK_USE_CONDENSED_INFO == 0
const SkMemberInfo SkAdd::fInfo[] = {
SK_MEMBER(mode, AddMode),
SK_MEMBER(offset, Int),
SK_MEMBER(use, Drawable),
SK_MEMBER(where, Drawable)
};
#endif
// start here;
// add onEndElement to turn where string into f_Where
// probably need new SkAnimateMaker::resolve flavor that takes
// where="id", where="event-target" or not-specified
// offset="#" (implements before, after, and index if no 'where')
DEFINE_GET_MEMBER(SkAdd);
SkAdd::SkAdd() : mode(kMode_indirect),
offset(SK_MaxS32), use(nullptr), where(nullptr) {
}
SkDisplayable* SkAdd::deepCopy(SkAnimateMaker* maker) {
SkADrawable* saveUse = use;
SkADrawable* saveWhere = where;
use = nullptr;
where = nullptr;
SkAdd* copy = (SkAdd*) INHERITED::deepCopy(maker);
copy->use = use = saveUse;
copy->where = where = saveWhere;
return copy;
}
bool SkAdd::draw(SkAnimateMaker& maker) {
SkASSERT(use);
SkASSERT(use->isDrawable());
if (mode == kMode_indirect)
use->draw(maker);
return false;
}
#ifdef SK_DUMP_ENABLED
void SkAdd::dump(SkAnimateMaker* maker) {
dumpBase(maker);
dumpAttrs(maker);
if (where)
SkDebugf("where=\"%s\" ", where->id);
if (mode == kMode_immediate)
SkDebugf("mode=\"immediate\" ");
SkDebugf(">\n");
SkDisplayList::fIndent += 4;
int save = SkDisplayList::fDumpIndex;
if (use) //just in case
use->dump(maker);
SkDisplayList::fIndent -= 4;
SkDisplayList::fDumpIndex = save;
dumpEnd(maker);
}
#endif
bool SkAdd::enable(SkAnimateMaker& maker ) {
SkDisplayTypes type = getType();
SkDisplayList& displayList = maker.fDisplayList;
SkTDDrawableArray* parentList = displayList.getDrawList();
if (type == SkType_Add) {
if (use == nullptr) // not set in apply yet
return true;
}
bool skipAddToParent = true;
SkASSERT(type != SkType_Replace || where);
SkTDDrawableArray* grandList SK_INIT_TO_AVOID_WARNING;
SkGroup* parentGroup = nullptr;
SkGroup* thisGroup = nullptr;
int index = where ? displayList.findGroup(where, &parentList, &parentGroup,
&thisGroup, &grandList) : 0;
if (index < 0)
return true;
int max = parentList->count();
if (where == nullptr && type == SkType_Move)
index = max;
if (offset != SK_MaxS32) {
index += offset;
if (index > max) {
maker.setErrorCode(SkDisplayXMLParserError::kIndexOutOfRange);
return true; // caller should not add
}
}
if (offset < 0 && where == nullptr)
index += max + 1;
switch (type) {
case SkType_Add:
if (offset == SK_MaxS32 && where == nullptr) {
if (use->isDrawable()) {
skipAddToParent = mode == kMode_immediate;
if (skipAddToParent) {
if (where == nullptr) {
SkTDDrawableArray* useParentList;
index = displayList.findGroup(this, &useParentList, &parentGroup,
&thisGroup, &grandList);
if (index >= 0) {
parentGroup->markCopySize(index);
parentGroup->markCopySet(index);
useParentList->begin()[index] = use;
break;
}
}
*parentList->append() = use;
}
}
break;
} else {
if (thisGroup)
thisGroup->markCopySize(index);
*parentList->insert(index) = use;
if (thisGroup)
thisGroup->markCopySet(index);
if (use->isApply())
((SkApply*) use)->setEmbedded();
}
break;
case SkType_Move: {
int priorLocation = parentList->find(use);
if (priorLocation < 0)
break;
*parentList->insert(index) = use;
if (index < priorLocation)
priorLocation++;
parentList->remove(priorLocation);
} break;
case SkType_Remove: {
SkDisplayable* old = (*parentList)[index];
if (((SkRemove*)(this))->fDelete) {
delete old;
goto noHelperNeeded;
}
for (int inner = 0; inner < maker.fChildren.count(); inner++) {
SkDisplayable* child = maker.fChildren[inner];
if (child == old || child->contains(old))
goto noHelperNeeded;
}
if (maker.fHelpers.find(old) < 0)
maker.helperAdd(old);
noHelperNeeded:
parentList->remove(index);
} break;
case SkType_Replace:
if (thisGroup) {
thisGroup->markCopySize(index);
if (thisGroup->markedForDelete(index)) {
SkDisplayable* old = (*parentList)[index];
if (maker.fHelpers.find(old) < 0)
maker.helperAdd(old);
}
}
(*parentList)[index] = use;
if (thisGroup)
thisGroup->markCopySet(index);
break;
default:
SkASSERT(0);
}
if (type == SkType_Remove)
return true;
if (use->hasEnable())
use->enable(maker);
return skipAddToParent; // append if indirect: *parentList->append() = this;
}
bool SkAdd::hasEnable() const {
return true;
}
void SkAdd::initialize() {
if (use)
use->initialize();
}
bool SkAdd::isDrawable() const {
return getType() == SkType_Add && mode == kMode_indirect && offset == SK_MaxS32 &&
where == nullptr && use != nullptr && use->isDrawable();
}
//SkDisplayable* SkAdd::resolveTarget(SkAnimateMaker& maker) {
// return use;
//}
bool SkClear::enable(SkAnimateMaker& maker ) {
SkDisplayList& displayList = maker.fDisplayList;
displayList.clear();
return true;
}
#if SK_USE_CONDENSED_INFO == 0
const SkMemberInfo SkMove::fInfo[] = {
SK_MEMBER_INHERITED
};
#endif
DEFINE_GET_MEMBER(SkMove);
#if SK_USE_CONDENSED_INFO == 0
const SkMemberInfo SkRemove::fInfo[] = {
SK_MEMBER_ALIAS(delete, fDelete, Boolean), // !!! experimental
SK_MEMBER(offset, Int),
SK_MEMBER(where, Drawable)
};
#endif
DEFINE_GET_MEMBER(SkRemove);
SkRemove::SkRemove() : fDelete(false) {
}
#if SK_USE_CONDENSED_INFO == 0
const SkMemberInfo SkReplace::fInfo[] = {
SK_MEMBER_INHERITED
};
#endif
DEFINE_GET_MEMBER(SkReplace);