Bug 1249443 - add AllChildrenIterator::GetPreviousChild, r=bz

This commit is contained in:
Alexander Surkov 2016-03-05 16:11:21 -05:00
parent a9d4eb0d80
commit e74f30bbd8
2 changed files with 108 additions and 31 deletions

View File

@ -314,24 +314,25 @@ ExplicitChildIterator::GetPreviousChild()
bool
AllChildrenIterator::Seek(nsIContent* aChildToFind)
{
if (mPhase == eNeedBeforeKid) {
mPhase = eNeedExplicitKids;
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
mPhase = eAtExplicitKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
if (beforeFrame->GetContent() == aChildToFind) {
mPhase = eAtBeforeKid;
return true;
}
}
}
}
if (mPhase == eNeedExplicitKids) {
if (mPhase == eAtExplicitKids) {
if (ExplicitChildIterator::Seek(aChildToFind)) {
return true;
}
mPhase = eNeedAnonKids;
mPhase = eAtAnonKids;
}
nsIContent* child = nullptr;
@ -345,59 +346,124 @@ AllChildrenIterator::Seek(nsIContent* aChildToFind)
nsIContent*
AllChildrenIterator::GetNextChild()
{
if (mPhase == eNeedBeforeKid) {
mPhase = eNeedExplicitKids;
if (mPhase == eAtBegin) {
mPhase = eAtExplicitKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
mPhase = eAtBeforeKid;
return beforeFrame->GetContent();
}
}
}
if (mPhase == eNeedExplicitKids) {
if (mPhase == eAtBeforeKid) {
// Advance into our explicit kids.
mPhase = eAtExplicitKids;
}
if (mPhase == eAtExplicitKids) {
nsIContent* kid = ExplicitChildIterator::GetNextChild();
if (kid) {
return kid;
}
mPhase = eNeedAnonKids;
mPhase = eAtAnonKids;
}
if (mPhase == eNeedAnonKids) {
if (mPhase == eAtAnonKids) {
if (mAnonKids.IsEmpty()) {
MOZ_ASSERT(mAnonKidsIdx == UINT32_MAX);
nsIAnonymousContentCreator* ac =
do_QueryFrame(mOriginalContent->GetPrimaryFrame());
if (ac) {
ac->AppendAnonymousContentTo(mAnonKids, mFlags);
}
mAnonKidsIdx = 0;
}
if (!mAnonKids.IsEmpty()) {
nsIContent* nextKid = mAnonKids[0];
mAnonKids.RemoveElementAt(0);
if (mAnonKids.IsEmpty()) {
mPhase = eNeedAfterKid;
else {
if (mAnonKidsIdx == UINT32_MAX) {
mAnonKidsIdx = 0;
}
else {
mAnonKidsIdx++;
}
return nextKid;
}
mPhase = eNeedAfterKid;
}
if (mAnonKidsIdx < mAnonKids.Length()) {
return mAnonKids[mAnonKidsIdx];
}
if (mPhase == eNeedAfterKid) {
mPhase = eDone;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
if (afterFrame) {
mPhase = eAtAfterKid;
return afterFrame->GetContent();
}
}
}
mPhase = eAtEnd;
return nullptr;
}
nsIContent*
AllChildrenIterator::GetPreviousChild()
{
if (mPhase == eAtEnd) {
MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length());
mPhase = eAtAnonKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
if (afterFrame) {
mPhase = eAtAfterKid;
return afterFrame->GetContent();
}
}
}
if (mPhase == eAtAfterKid) {
mPhase = eAtAnonKids;
}
if (mPhase == eAtAnonKids) {
if (mAnonKids.IsEmpty()) {
nsIAnonymousContentCreator* ac =
do_QueryFrame(mOriginalContent->GetPrimaryFrame());
if (ac) {
ac->AppendAnonymousContentTo(mAnonKids, mFlags);
mAnonKidsIdx = mAnonKids.Length();
}
}
// If 0 then it turns into UINT32_MAX, which indicates the iterator is
// before the anonymous children.
--mAnonKidsIdx;
if (mAnonKidsIdx < mAnonKids.Length()) {
return mAnonKids[mAnonKidsIdx];
}
mPhase = eAtExplicitKids;
}
if (mPhase == eAtExplicitKids) {
nsIContent* kid = ExplicitChildIterator::GetPreviousChild();
if (kid) {
return kid;
}
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
mPhase = eAtBeforeKid;
return beforeFrame->GetContent();
}
}
}
mPhase = eAtBegin;
return nullptr;
}

View File

@ -182,14 +182,14 @@ class AllChildrenIterator : private FlattenedChildIterator
public:
AllChildrenIterator(nsIContent* aNode, uint32_t aFlags, bool aStartAtBeginning = true) :
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
mOriginalContent(aNode), mFlags(aFlags),
mPhase(eNeedBeforeKid) {}
mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
AllChildrenIterator(AllChildrenIterator&& aOther)
: FlattenedChildIterator(Move(aOther)),
mOriginalContent(aOther.mOriginalContent),
mAnonKids(Move(aOther.mAnonKids)), mFlags(aOther.mFlags),
mPhase(aOther.mPhase)
mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
mFlags(aOther.mFlags), mPhase(aOther.mPhase)
#ifdef DEBUG
, mMutationGuard(aOther.mMutationGuard)
#endif
@ -202,20 +202,31 @@ public:
bool Seek(nsIContent* aChildToFind);
nsIContent* GetNextChild();
nsIContent* GetPreviousChild();
nsIContent* Parent() const { return mOriginalContent; }
private:
enum IteratorPhase
{
eNeedBeforeKid,
eNeedExplicitKids,
eNeedAnonKids,
eNeedAfterKid,
eDone
eAtBegin,
eAtBeforeKid,
eAtExplicitKids,
eAtAnonKids,
eAtAfterKid,
eAtEnd
};
nsIContent* mOriginalContent;
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
// in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
// eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
// mAnonKidsIdx == mAnonKids.Length() then the iterator is somewhere after
// the last native anon child. If mAnonKidsIdx == UINT32_MAX then the iterator
// is somewhere before the first native anon child.
nsTArray<nsIContent*> mAnonKids;
uint32_t mAnonKidsIdx;
uint32_t mFlags;
IteratorPhase mPhase;
#ifdef DEBUG