diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 68a706531b69..228f22c3915e 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -409,7 +409,11 @@ nsINode::ChildNodes() { nsSlots* slots = Slots(); if (!slots->mChildNodes) { - slots->mChildNodes = new nsAttrChildContentList(this); + // Check |!IsElement()| first to catch the common case + // without virtual call |IsNodeOfType| + slots->mChildNodes = !IsElement() && IsNodeOfType(nsINode::eATTRIBUTE) ? + new nsAttrChildContentList(this) : + new nsParentNodeChildContentList(this); } return slots->mChildNodes; @@ -1562,8 +1566,9 @@ nsresult nsINode::doInsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify, nsAttrAndChildArray& aChildArray) { - NS_PRECONDITION(!aKid->GetParentNode(), - "Inserting node that already has parent"); + MOZ_ASSERT(!aKid->GetParentNode(), "Inserting node that already has parent"); + MOZ_ASSERT(!IsNodeOfType(nsINode::eATTRIBUTE)); + nsresult rv; // The id-handling code, and in the future possibly other code, need to @@ -1592,6 +1597,14 @@ nsINode::doInsertChildAt(nsIContent* aKid, uint32_t aIndex, mFirstChild = aKid; } + // Invalidate cached array of child nodes + nsSlots* slots = GetExistingSlots(); + if (slots && slots->mChildNodes) { + auto childNodes = + static_cast(slots->mChildNodes.get()); + childNodes->InvalidateCache(); + } + nsIContent* parent = IsNodeOfType(eDOCUMENT) ? nullptr : static_cast(this); @@ -1897,9 +1910,10 @@ nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify, // nsIDocument::GetRootElement() calls until *after* it has removed aKid from // aChildArray. Any calls before then could potentially restore a stale // value for our cached root element, per note in nsDocument::RemoveChildAt(). - NS_PRECONDITION(aKid && aKid->GetParentNode() == this && - aKid == GetChildAt(aIndex) && - IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid"); + MOZ_ASSERT(aKid && aKid->GetParentNode() == this && + aKid == GetChildAt(aIndex) && + IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid"); + MOZ_ASSERT(!IsNodeOfType(nsINode::eATTRIBUTE)); nsMutationGuard::DidMutate(); mozAutoDocUpdate updateBatch(GetComposedDoc(), UPDATE_CONTENT_MODEL, aNotify); @@ -1912,6 +1926,14 @@ nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify, aChildArray.RemoveChildAt(aIndex); + // Invalidate cached array of child nodes + nsSlots* slots = GetExistingSlots(); + if (slots && slots->mChildNodes) { + auto childNodes = + static_cast(slots->mChildNodes.get()); + childNodes->InvalidateCache(); + } + if (aNotify) { nsNodeUtils::ContentRemoved(this, aKid, aIndex, previousSibling); }