Bug 1384661 - Part 2: Add class nsParentNodeChildContentList. r=smaug
authorbtian <btian@mozilla.com>
Mon, 21 Aug 2017 16:11:56 +0800
changeset 425784 8f77d260780d5b9b6e49d26d723f3d7b3a5f6f7a
parent 425783 b679806ce7e389cc76cd5f72c84f929004311e55
child 425785 7df868e0e3567d894b2d245fd81c198011c40535
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1384661
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1384661 - Part 2: Add class nsParentNodeChildContentList. r=smaug
dom/base/FragmentOrElement.cpp
dom/base/nsChildContentList.h
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -593,16 +593,87 @@ nsAttrChildContentList::IndexOf(nsIConte
   if (mNode) {
     return mNode->IndexOf(aContent);
   }
 
   return -1;
 }
 
 //----------------------------------------------------------------------
+NS_IMETHODIMP
+nsParentNodeChildContentList::GetLength(uint32_t* aLength)
+{
+  if (!mIsCacheValid && !ValidateCache()) {
+    *aLength = 0;
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(mIsCacheValid);
+
+  *aLength = mCachedChildArray.Length();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsParentNodeChildContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
+{
+  nsINode* node = Item(aIndex);
+  if (!node) {
+    *aReturn = nullptr;
+    return NS_OK;
+  }
+
+  return CallQueryInterface(node, aReturn);
+}
+
+nsIContent*
+nsParentNodeChildContentList::Item(uint32_t aIndex)
+{
+  if (!mIsCacheValid && !ValidateCache()) {
+    return nullptr;
+  }
+
+  MOZ_ASSERT(mIsCacheValid);
+
+  return mCachedChildArray.SafeElementAt(aIndex, nullptr);
+}
+
+int32_t
+nsParentNodeChildContentList::IndexOf(nsIContent* aContent)
+{
+  if (!mIsCacheValid && !ValidateCache()) {
+    return -1;
+  }
+
+  MOZ_ASSERT(mIsCacheValid);
+
+  return mCachedChildArray.IndexOf(aContent);
+}
+
+bool
+nsParentNodeChildContentList::ValidateCache()
+{
+  MOZ_ASSERT(!mIsCacheValid);
+  MOZ_ASSERT(mCachedChildArray.IsEmpty());
+
+  nsINode* parent = GetParentObject();
+  if (!parent) {
+    return false;
+  }
+
+  for (nsIContent* node = parent->GetFirstChild(); node;
+       node = node->GetNextSibling()) {
+    mCachedChildArray.AppendElement(node);
+  }
+  mIsCacheValid = true;
+
+  return true;
+}
+
+//----------------------------------------------------------------------
 
 nsIHTMLCollection*
 FragmentOrElement::Children()
 {
   FragmentOrElement::nsDOMSlots *slots = DOMSlots();
 
   if (!slots->mChildrenList) {
     slots->mChildrenList = new nsContentList(this, kNameSpaceID_Wildcard,
--- a/dom/base/nsChildContentList.h
+++ b/dom/base/nsChildContentList.h
@@ -3,29 +3,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsChildContentList_h__
 #define nsChildContentList_h__
 
 #include "nsISupportsImpl.h"
-#include "nsINodeList.h"            // base class
+#include "nsINodeList.h"      // base class
 #include "js/TypeDecls.h"     // for Handle, Value, JSObject, JSContext
 
 class nsIContent;
 class nsINode;
 
 /**
  * Class that implements the nsIDOMNodeList interface (a list of children of
  * the content), by holding a reference to the content and delegating GetLength
  * and Item to its existing child list.
  * @see nsIDOMNodeList
  */
-class nsAttrChildContentList final : public nsINodeList
+class nsAttrChildContentList : public nsINodeList
 {
 public:
   explicit nsAttrChildContentList(nsINode* aNode)
     : mNode(aNode)
   {
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -37,28 +37,71 @@ public:
 
   // nsIDOMNodeList interface
   NS_DECL_NSIDOMNODELIST
 
   // nsINodeList interface
   virtual int32_t IndexOf(nsIContent* aContent) override;
   virtual nsIContent* Item(uint32_t aIndex) override;
 
-  void DropReference()
+  virtual void DropReference()
   {
     mNode = nullptr;
   }
 
   virtual nsINode* GetParentObject() override
   {
     return mNode;
   }
 
+protected:
+  virtual ~nsAttrChildContentList() {}
+
 private:
-  ~nsAttrChildContentList() {}
-
   // The node whose children make up the list.
   // This is a non-owning ref which is safe because it's set to nullptr by
   // DropReference() by the node slots get destroyed.
   nsINode* MOZ_NON_OWNING_REF mNode;
 };
 
+class nsParentNodeChildContentList final : public nsAttrChildContentList
+{
+public:
+  explicit nsParentNodeChildContentList(nsINode* aNode)
+    : nsAttrChildContentList(aNode)
+    , mIsCacheValid(false)
+  {
+    ValidateCache();
+  }
+
+  // nsIDOMNodeList interface
+  NS_DECL_NSIDOMNODELIST
+
+  // nsINodeList interface
+  virtual int32_t IndexOf(nsIContent* aContent) override;
+  virtual nsIContent* Item(uint32_t aIndex) override;
+
+  void DropReference() override
+  {
+    InvalidateCache();
+    nsAttrChildContentList::DropReference();
+  }
+
+  void InvalidateCache()
+  {
+    mIsCacheValid = false;
+    mCachedChildArray.Clear();
+  }
+
+private:
+  ~nsParentNodeChildContentList() {}
+
+  // Return true if validation succeeds, false otherwise
+  bool ValidateCache();
+
+  // Whether cached array of child nodes is valid
+  bool mIsCacheValid;
+
+  // Cached array of child nodes
+  AutoTArray<nsIContent*, 8> mCachedChildArray;
+};
+
 #endif /* nsChildContentList_h__ */