Bug 564435. Use iterative tree traversals in nsContentList so as to speed it up. r=sicking

This commit is contained in:
Boris Zbarsky 2010-05-10 21:12:34 -04:00
Родитель 4f32f7ec2a
Коммит 554a7ccc9a
2 изменённых файлов: 50 добавлений и 135 удалений

Просмотреть файл

@ -683,10 +683,10 @@ nsContentList::ContentAppended(nsIDocument *aDocument, nsIContent* aContainer,
if (!appendToList) {
// The new stuff is somewhere in the middle of our list; check
// whether we need to invalidate
for (nsINode::ChildIterator iter(aContainer, aNewIndexInContainer);
!iter.IsDone();
iter.Next()) {
if (MatchSelf(iter)) {
for (nsIContent* cur = aContainer->GetChildAt(aNewIndexInContainer);
cur;
cur = cur->GetNextSibling()) {
if (MatchSelf(cur)) {
// Uh-oh. We're gonna have to add elements into the middle
// of our list. That's not worth the effort.
SetDirty();
@ -711,13 +711,21 @@ nsContentList::ContentAppended(nsIDocument *aDocument, nsIContent* aContainer,
* We're up to date. That means someone's actively using us; we
* may as well grab this content....
*/
for (nsINode::ChildIterator iter(aContainer, aNewIndexInContainer);
!iter.IsDone();
iter.Next()) {
PRUint32 limit = PRUint32(-1);
nsIContent* newContent = iter;
if (newContent->IsElement()) {
PopulateWith(newContent->AsElement(), limit);
if (mDeep) {
for (nsIContent* cur = aContainer->GetChildAt(aNewIndexInContainer);
cur;
cur = cur->GetNextNode(aContainer)) {
if (cur->IsElement() && Match(cur->AsElement())) {
mElements.AppendObject(cur);
}
}
} else {
for (nsIContent* cur = aContainer->GetChildAt(aNewIndexInContainer);
cur;
cur = cur->GetNextSibling()) {
if (cur->IsElement() && Match(cur->AsElement())) {
mElements.AppendObject(cur);
}
}
}
@ -805,8 +813,10 @@ nsContentList::MatchSelf(nsIContent *aContent)
if (!mDeep)
return PR_FALSE;
for (nsINode::ChildIterator iter(aContent); !iter.IsDone(); iter.Next()) {
if (MatchSelf(iter)) {
for (nsIContent* cur = aContent->GetFirstChild();
cur;
cur = cur->GetNextNode(aContent)) {
if (cur->IsElement() && Match(cur->AsElement())) {
return PR_TRUE;
}
}
@ -814,91 +824,6 @@ nsContentList::MatchSelf(nsIContent *aContent)
return PR_FALSE;
}
void
nsContentList::PopulateWith(Element *aElement, PRUint32& aElementsToAppend)
{
NS_PRECONDITION(mDeep || aElement->GetNodeParent() == mRootNode,
"PopulateWith called on nodes we can't possibly match");
NS_PRECONDITION(aElement != mRootNode,
"We should never be trying to match mRootNode");
if (Match(aElement)) {
mElements.AppendObject(aElement);
--aElementsToAppend;
if (aElementsToAppend == 0)
return;
}
// Don't recurse down if we're not doing a deep match.
if (!mDeep)
return;
for (nsINode::ChildIterator iter(aElement); !iter.IsDone(); iter.Next()) {
nsIContent* curContent = iter;
if (curContent->IsElement()) {
PopulateWith(curContent->AsElement(), aElementsToAppend);
if (aElementsToAppend == 0)
break;
}
}
}
void
nsContentList::PopulateWithStartingAfter(nsINode *aStartRoot,
nsINode *aStartChild,
PRUint32 & aElementsToAppend)
{
NS_PRECONDITION(mDeep || aStartRoot == mRootNode ||
(aStartRoot->GetNodeParent() == mRootNode &&
aStartChild == nsnull),
"Bogus aStartRoot or aStartChild");
if (mDeep || aStartRoot == mRootNode) {
#ifdef DEBUG
PRUint32 invariant = aElementsToAppend + mElements.Count();
#endif
PRInt32 i = 0;
if (aStartChild) {
i = aStartRoot->IndexOf(aStartChild);
NS_ASSERTION(i >= 0, "The start child must be a child of the start root!");
++i; // move to one past
}
// Now start an iterator with the child we want to be starting with
for (nsINode::ChildIterator iter(aStartRoot, i);
!iter.IsDone();
iter.Next()) {
nsIContent* content = iter;
if (content->IsElement()) {
PopulateWith(content->AsElement(), aElementsToAppend);
NS_ASSERTION(aElementsToAppend + mElements.Count() == invariant,
"Something is awry in PopulateWith!");
if (aElementsToAppend == 0)
break;
}
}
}
if (aElementsToAppend == 0) {
return;
}
// We want to make sure we don't move up past our root node. So if
// we're there, don't move to the parent.
if (aStartRoot == mRootNode)
return;
// We could call GetParent() here to avoid walking children of the
// document node. However they should be very few in number and we
// might want to walk them in the future so it's unnecessary to have
// this be the only thing that prevents it
nsINode* parent = aStartRoot->GetNodeParent();
if (parent)
PopulateWithStartingAfter(parent, aStartRoot, aElementsToAppend);
}
void
nsContentList::PopulateSelf(PRUint32 aNeededLength)
{
@ -920,13 +845,33 @@ nsContentList::PopulateSelf(PRUint32 aNeededLength)
PRUint32 invariant = elementsToAppend + mElements.Count();
#endif
// If we already have nodes start searching at the last one, otherwise
// start searching at the root.
nsINode* startRoot = count == 0 ? mRootNode : mElements[count - 1];
if (mDeep) {
// If we already have nodes start searching at the last one, otherwise
// start searching at the root.
nsINode* cur = count ? mElements[count - 1] : mRootNode;
do {
cur = cur->GetNextNode(mRootNode);
if (!cur) {
break;
}
if (cur->IsElement() && Match(cur->AsElement())) {
mElements.AppendObject(cur->AsElement());
--elementsToAppend;
}
} while (elementsToAppend);
} else {
nsIContent* cur =
count ? mElements[count-1]->GetNextSibling() : mRootNode->GetFirstChild();
for ( ; cur && elementsToAppend; cur = cur->GetNextSibling()) {
if (cur->IsElement() && Match(cur->AsElement())) {
mElements.AppendObject(cur);
--elementsToAppend;
}
}
}
PopulateWithStartingAfter(startRoot, nsnull, elementsToAppend);
NS_ASSERTION(elementsToAppend + mElements.Count() == invariant,
"Something is awry in PopulateWith!");
"Something is awry!");
if (elementsToAppend != 0)
mState = LIST_UP_TO_DATE;

Просмотреть файл

@ -315,44 +315,14 @@ protected:
*/
PRBool Match(mozilla::dom::Element *aElement);
/**
* Match recursively. See if anything in the subtree rooted at
* aContent matches our criterion.
* See if anything in the subtree rooted at aContent, including
* aContent itself, matches our criterion.
*
* @param aContent the root of the subtree to match against
* @return whether we match something in the tree rooted at aContent
*/
PRBool MatchSelf(nsIContent *aContent);
/**
* Add elements in the subtree rooted in aElement that match our
* criterion to our list until we've picked up aElementsToAppend
* elements. This function enforces the invariant that
* |aElementsToAppend + mElements.Count()| is a constant.
*
* @param aElement the root of the subtree we want to traverse. This element
* is always included in the traversal and is thus the
* first element tested.
* @param aElementsToAppend how many elements to append to the list
* before stopping
*/
void NS_FASTCALL PopulateWith(mozilla::dom::Element *aElement,
PRUint32 & aElementsToAppend);
/**
* Populate our list starting at the child of aStartRoot that comes
* after aStartChild (if such exists) and continuing in document
* order. Stop once we've picked up aElementsToAppend elements.
* This function enforces the invariant that |aElementsToAppend +
* mElements.Count()| is a constant.
*
* @param aStartRoot the node with whose children we want to start traversal
* @param aStartChild the child after which we want to start
* @param aElementsToAppend how many elements to append to the list
* before stopping
*/
void PopulateWithStartingAfter(nsINode *aStartRoot,
nsINode *aStartChild,
PRUint32 & aElementsToAppend);
/**
* Populate our list. Stop once we have at least aNeededLength
* elements. At the end of PopulateSelf running, either the last