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 bool
AllChildrenIterator::Seek(nsIContent* aChildToFind) AllChildrenIterator::Seek(nsIContent* aChildToFind)
{ {
if (mPhase == eNeedBeforeKid) { if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
mPhase = eNeedExplicitKids; mPhase = eAtExplicitKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame(); nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) { if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame); nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) { if (beforeFrame) {
if (beforeFrame->GetContent() == aChildToFind) { if (beforeFrame->GetContent() == aChildToFind) {
mPhase = eAtBeforeKid;
return true; return true;
} }
} }
} }
} }
if (mPhase == eNeedExplicitKids) { if (mPhase == eAtExplicitKids) {
if (ExplicitChildIterator::Seek(aChildToFind)) { if (ExplicitChildIterator::Seek(aChildToFind)) {
return true; return true;
} }
mPhase = eNeedAnonKids; mPhase = eAtAnonKids;
} }
nsIContent* child = nullptr; nsIContent* child = nullptr;
@ -345,59 +346,124 @@ AllChildrenIterator::Seek(nsIContent* aChildToFind)
nsIContent* nsIContent*
AllChildrenIterator::GetNextChild() AllChildrenIterator::GetNextChild()
{ {
if (mPhase == eNeedBeforeKid) { if (mPhase == eAtBegin) {
mPhase = eNeedExplicitKids; mPhase = eAtExplicitKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame(); nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) { if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame); nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) { if (beforeFrame) {
mPhase = eAtBeforeKid;
return beforeFrame->GetContent(); return beforeFrame->GetContent();
} }
} }
} }
if (mPhase == eNeedExplicitKids) { if (mPhase == eAtBeforeKid) {
// Advance into our explicit kids.
mPhase = eAtExplicitKids;
}
if (mPhase == eAtExplicitKids) {
nsIContent* kid = ExplicitChildIterator::GetNextChild(); nsIContent* kid = ExplicitChildIterator::GetNextChild();
if (kid) { if (kid) {
return kid; return kid;
} }
mPhase = eAtAnonKids;
mPhase = eNeedAnonKids;
} }
if (mPhase == eNeedAnonKids) { if (mPhase == eAtAnonKids) {
if (mAnonKids.IsEmpty()) { if (mAnonKids.IsEmpty()) {
MOZ_ASSERT(mAnonKidsIdx == UINT32_MAX);
nsIAnonymousContentCreator* ac = nsIAnonymousContentCreator* ac =
do_QueryFrame(mOriginalContent->GetPrimaryFrame()); do_QueryFrame(mOriginalContent->GetPrimaryFrame());
if (ac) { if (ac) {
ac->AppendAnonymousContentTo(mAnonKids, mFlags); ac->AppendAnonymousContentTo(mAnonKids, mFlags);
} }
mAnonKidsIdx = 0;
} }
else {
if (!mAnonKids.IsEmpty()) { if (mAnonKidsIdx == UINT32_MAX) {
nsIContent* nextKid = mAnonKids[0]; mAnonKidsIdx = 0;
mAnonKids.RemoveElementAt(0); }
if (mAnonKids.IsEmpty()) { else {
mPhase = eNeedAfterKid; mAnonKidsIdx++;
} }
return nextKid;
} }
mPhase = eNeedAfterKid; if (mAnonKidsIdx < mAnonKids.Length()) {
} return mAnonKids[mAnonKidsIdx];
}
if (mPhase == eNeedAfterKid) {
mPhase = eDone;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame(); nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) { if (frame) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame); nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
if (afterFrame) { if (afterFrame) {
mPhase = eAtAfterKid;
return afterFrame->GetContent(); 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; return nullptr;
} }

View File

@ -182,14 +182,14 @@ class AllChildrenIterator : private FlattenedChildIterator
public: public:
AllChildrenIterator(nsIContent* aNode, uint32_t aFlags, bool aStartAtBeginning = true) : AllChildrenIterator(nsIContent* aNode, uint32_t aFlags, bool aStartAtBeginning = true) :
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning), FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
mOriginalContent(aNode), mFlags(aFlags), mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
mPhase(eNeedBeforeKid) {} mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
AllChildrenIterator(AllChildrenIterator&& aOther) AllChildrenIterator(AllChildrenIterator&& aOther)
: FlattenedChildIterator(Move(aOther)), : FlattenedChildIterator(Move(aOther)),
mOriginalContent(aOther.mOriginalContent), mOriginalContent(aOther.mOriginalContent),
mAnonKids(Move(aOther.mAnonKids)), mFlags(aOther.mFlags), mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
mPhase(aOther.mPhase) mFlags(aOther.mFlags), mPhase(aOther.mPhase)
#ifdef DEBUG #ifdef DEBUG
, mMutationGuard(aOther.mMutationGuard) , mMutationGuard(aOther.mMutationGuard)
#endif #endif
@ -202,20 +202,31 @@ public:
bool Seek(nsIContent* aChildToFind); bool Seek(nsIContent* aChildToFind);
nsIContent* GetNextChild(); nsIContent* GetNextChild();
nsIContent* GetPreviousChild();
nsIContent* Parent() const { return mOriginalContent; } nsIContent* Parent() const { return mOriginalContent; }
private: private:
enum IteratorPhase enum IteratorPhase
{ {
eNeedBeforeKid, eAtBegin,
eNeedExplicitKids, eAtBeforeKid,
eNeedAnonKids, eAtExplicitKids,
eNeedAfterKid, eAtAnonKids,
eDone eAtAfterKid,
eAtEnd
}; };
nsIContent* mOriginalContent; 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; nsTArray<nsIContent*> mAnonKids;
uint32_t mAnonKidsIdx;
uint32_t mFlags; uint32_t mFlags;
IteratorPhase mPhase; IteratorPhase mPhase;
#ifdef DEBUG #ifdef DEBUG