Bug 895974. Implement ParentNode on document fragments and documents and move previousElementSibling and nextElementSibling to ChildNode. r=smaug
☠☠ backed out by 3794beed0e34 ☠ ☠
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 22 Jul 2013 08:15:43 -0400
changeset 151731 0a196c0e9f96e4cf579a69a7ccdcca23e24418ba
parent 151730 0d8aa14f5ed3545c7108899a29154a80466203bb
child 151732 b1622b3acf58862785b62096bc2211af9bd461c8
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs895974
milestone25.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 895974. Implement ParentNode on document fragments and documents and move previousElementSibling and nextElementSibling to ChildNode. r=smaug
content/base/public/Element.h
content/base/public/FragmentOrElement.h
content/base/public/nsIDocument.h
content/base/public/nsINode.h
content/base/src/Element.cpp
content/base/src/nsDocument.cpp
content/base/src/nsINode.cpp
content/base/test/Makefile.in
content/base/test/test_bug895974.html
dom/webidl/ChildNode.webidl
dom/webidl/Document.webidl
dom/webidl/DocumentFragment.webidl
dom/webidl/Element.webidl
dom/webidl/ParentNode.webidl
dom/webidl/WebIDL.mk
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -33,17 +33,16 @@
 #include "nsContentUtils.h"
 #include "nsIScrollableFrame.h"
 #include "mozilla/dom/Attr.h"
 #include "nsISMILAttr.h"
 #include "nsClientRect.h"
 #include "nsEvent.h"
 #include "nsAttrValue.h"
 #include "mozilla/dom/BindingDeclarations.h"
-#include "nsIHTMLCollection.h"
 #include "Units.h"
 
 class nsIDOMEventListener;
 class nsIFrame;
 class nsIDOMMozNamedAttrMap;
 class nsIDOMCSSStyleDeclaration;
 class nsIURI;
 class nsINodeInfo;
@@ -595,46 +594,16 @@ public:
   already_AddRefed<nsIHTMLCollection>
     GetElementsByTagName(const nsAString& aQualifiedName);
   already_AddRefed<nsIHTMLCollection>
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                            const nsAString& aLocalName,
                            ErrorResult& aError);
   already_AddRefed<nsIHTMLCollection>
     GetElementsByClassName(const nsAString& aClassNames);
-  Element* GetFirstElementChild() const;
-  Element* GetLastElementChild() const;
-  Element* GetPreviousElementSibling() const
-  {
-    nsIContent* previousSibling = GetPreviousSibling();
-    while (previousSibling) {
-      if (previousSibling->IsElement()) {
-        return previousSibling->AsElement();
-      }
-      previousSibling = previousSibling->GetPreviousSibling();
-    }
-
-    return nullptr;
-  }
-  Element* GetNextElementSibling() const
-  {
-    nsIContent* nextSibling = GetNextSibling();
-    while (nextSibling) {
-      if (nextSibling->IsElement()) {
-        return nextSibling->AsElement();
-      }
-      nextSibling = nextSibling->GetNextSibling();
-    }
-
-    return nullptr;
-  }
-  uint32_t ChildElementCount()
-  {
-    return Children()->Length();
-  }
   bool MozMatchesSelector(const nsAString& aSelector,
                           ErrorResult& aError);
   void SetCapture(bool aRetargetToElement)
   {
     // If there is already an active capture, ignore this request. This would
     // occur if a splitter, frame resizer, etc had already captured and we don't
     // want to override those.
     if (!nsIPresShell::GetCapturingContent()) {
--- a/content/base/public/FragmentOrElement.h
+++ b/content/base/public/FragmentOrElement.h
@@ -18,26 +18,26 @@
 #include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
 #include "nsIContent.h"                   // base class
 #include "nsIDOMTouchEvent.h"             // base class (nsITouchEventReceiver)
 #include "nsIDOMXPathNSResolver.h"        // base class
 #include "nsIInlineEventHandlers.h"       // base class
 #include "nsINodeList.h"                  // base class
 #include "nsIWeakReference.h"             // base class
 #include "nsNodeUtils.h"                  // class member nsNodeUtils::CloneNodeImpl
+#include "nsIHTMLCollection.h"
 
 class ContentUnbinder;
 class nsContentList;
 class nsDOMAttributeMap;
 class nsDOMTokenList;
 class nsIControllers;
 class nsICSSDeclaration;
 class nsIDocument;
 class nsDOMStringMap;
-class nsIHTMLCollection;
 class nsINodeInfo;
 class nsIURI;
 
 /**
  * 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
@@ -224,16 +224,20 @@ public:
 
   virtual void DestroyContent() MOZ_OVERRIDE;
   virtual void SaveSubtreeState() MOZ_OVERRIDE;
 
   virtual const nsAttrValue* DoGetClasses() const MOZ_OVERRIDE;
   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) MOZ_OVERRIDE;
 
   nsIHTMLCollection* Children();
+  uint32_t ChildElementCount()
+  {
+    return Children()->Length();
+  }
 
 public:
   /**
    * If there are listeners for DOMNodeInserted event, fires the event on all
    * aNodes
    */
   static void FireNodeInserted(nsIDocument* aDoc,
                                nsINode* aParent,
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -48,16 +48,17 @@ class nsIDocShell;
 class nsIDocumentObserver;
 class nsIDOMDocument;
 class nsIDOMDocumentFragment;
 class nsIDOMDocumentType;
 class nsIDOMElement;
 class nsIDOMNodeList;
 class nsIDOMXPathExpression;
 class nsIDOMXPathNSResolver;
+class nsIHTMLCollection;
 class nsILayoutHistoryState;
 class nsIObjectLoadingContent;
 class nsIObserver;
 class nsIPresShell;
 class nsIPrincipal;
 class nsIRequest;
 class nsIStreamListener;
 class nsIStyleRule;
@@ -2115,16 +2116,20 @@ public:
   {
     return mStyleSheetChangeEventsEnabled;
   }
 
   void ObsoleteSheet(nsIURI *aSheetURI, mozilla::ErrorResult& rv);
 
   void ObsoleteSheet(const nsAString& aSheetURI, mozilla::ErrorResult& rv);
 
+  // ParentNode
+  nsIHTMLCollection* Children();
+  uint32_t ChildElementCount();
+
   virtual nsHTMLDocument* AsHTMLDocument() { return nullptr; }
 
   virtual JSObject* WrapObject(JSContext *aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 private:
   uint64_t mWarnedAbout;
 
@@ -2206,16 +2211,19 @@ protected:
 
   // SMIL Animation Controller, lazily-initialized in GetAnimationController
   nsRefPtr<nsSMILAnimationController> mAnimationController;
 
   // Table of element properties for this document.
   nsPropertyTable mPropertyTable;
   nsTArray<nsAutoPtr<nsPropertyTable> > mExtraPropertyTables;
 
+  // Our cached .children collection
+  nsCOMPtr<nsIHTMLCollection> mChildrenCollection;
+
   // Compatibility mode
   nsCompatibility mCompatMode;
 
   // Our readyState
   ReadyState mReadyState;
 
   // Our visibility state
   mozilla::dom::VisibilityState mVisibilityState;
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -1585,21 +1585,28 @@ public:
   nsresult RemoveFromParent()
   {
     nsINode* parent = GetParentNode();
     mozilla::ErrorResult rv;
     parent->RemoveChild(*this, rv);
     return rv.ErrorCode();
   }
 
+  // ChildNode methods
+  mozilla::dom::Element* GetPreviousElementSibling() const;
+  mozilla::dom::Element* GetNextElementSibling() const;
   /**
    * Remove this node from its parent, if any.
    */
   void Remove();
 
+  // ParentNode methods
+  mozilla::dom::Element* GetFirstElementChild() const;
+  mozilla::dom::Element* GetLastElementChild() const;
+
 protected:
 
   // Override this function to create a custom slots class.
   // Must not return null.
   virtual nsINode::nsSlots* CreateSlots();
 
   bool HasSlots() const
   {
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -411,44 +411,16 @@ Element::WrapObject(JSContext *aCx, JS::
       nsContentUtils::AddScriptRunner(
         NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
     }
   }
 
   return obj;
 }
 
-Element*
-Element::GetFirstElementChild() const
-{
-  uint32_t i, count = mAttrsAndChildren.ChildCount();
-  for (i = 0; i < count; ++i) {
-    nsIContent* child = mAttrsAndChildren.ChildAt(i);
-    if (child->IsElement()) {
-      return child->AsElement();
-    }
-  }
-  
-  return nullptr;
-}
-
-Element*
-Element::GetLastElementChild() const
-{
-  uint32_t i = mAttrsAndChildren.ChildCount();
-  while (i > 0) {
-    nsIContent* child = mAttrsAndChildren.ChildAt(--i);
-    if (child->IsElement()) {
-      return child->AsElement();
-    }
-  }
-  
-  return nullptr;
-}
-
 nsDOMTokenList*
 Element::GetClassList()
 {
   Element::nsDOMSlots *slots = DOMSlots();
 
   if (!slots->mClassList) {
     nsIAtom* classAttr = GetClassAttributeName();
     if (classAttr) {
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1788,16 +1788,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUndoManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection)
 
   // Traverse all our nsCOMArrays.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCatalogSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
 
   for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
@@ -1872,16 +1873,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFirstBaseNodeWithHref)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mUndoManager)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection)
 
   tmp->mParentDocument = nullptr;
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages)
 
 
   if (tmp->mBoxObjectTable) {
    tmp->mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nullptr);
@@ -9470,16 +9472,35 @@ nsIDocument::ObsoleteSheet(const nsAStri
     return;
   }
   res = CSSLoader()->ObsoleteSheet(uri);
   if (NS_FAILED(res)) {
     rv.Throw(res);
   }
 }
 
+nsIHTMLCollection*
+nsIDocument::Children()
+{
+  if (!mChildrenCollection) {
+    mChildrenCollection = new nsContentList(this, kNameSpaceID_Wildcard,
+                                            nsGkAtoms::_asterix,
+                                            nsGkAtoms::_asterix,
+                                            false);
+  }
+
+  return mChildrenCollection;
+}
+
+uint32_t
+nsIDocument::ChildElementCount()
+{
+  return Children()->Length();
+}
+
 namespace mozilla {
 
 // Singleton class to manage the list of fullscreen documents which are the
 // root of a branch which contains fullscreen documents. We maintain this list
 // so that we can easily exit all windows from fullscreen when the user
 // presses the escape key.
 class FullscreenRoots {
 public:
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -1399,31 +1399,87 @@ nsINode::doInsertChildAt(nsIContent* aKi
       mozAutoSubtreeModified subtree(OwnerDoc(), this);
       (new nsAsyncDOMEvent(aKid, mutation))->RunDOMEventWhenSafe();
     }
   }
 
   return NS_OK;
 }
 
+Element*
+nsINode::GetPreviousElementSibling() const
+{
+  nsIContent* previousSibling = GetPreviousSibling();
+  while (previousSibling) {
+    if (previousSibling->IsElement()) {
+      return previousSibling->AsElement();
+    }
+    previousSibling = previousSibling->GetPreviousSibling();
+  }
+
+  return nullptr;
+}
+
+Element*
+nsINode::GetNextElementSibling() const
+{
+  nsIContent* nextSibling = GetNextSibling();
+  while (nextSibling) {
+    if (nextSibling->IsElement()) {
+      return nextSibling->AsElement();
+    }
+    nextSibling = nextSibling->GetNextSibling();
+  }
+
+  return nullptr;
+}
+
 void
 nsINode::Remove()
 {
   nsCOMPtr<nsINode> parent = GetParentNode();
   if (!parent) {
     return;
   }
   int32_t index = parent->IndexOf(this);
   if (index < 0) {
     NS_WARNING("Ignoring call to nsINode::Remove on anonymous child.");
     return;
   }
   parent->RemoveChildAt(uint32_t(index), true);
 }
 
+Element*
+nsINode::GetFirstElementChild() const
+{
+  for (nsIContent* child = GetFirstChild();
+       child;
+       child = child->GetNextSibling()) {
+    if (child->IsElement()) {
+      return child->AsElement();
+    }
+  }
+
+  return nullptr;
+}
+
+Element*
+nsINode::GetLastElementChild() const
+{
+  for (nsIContent* child = GetLastChild();
+       child;
+       child = child->GetPreviousSibling()) {
+    if (child->IsElement()) {
+      return child->AsElement();
+    }
+  }
+
+  return nullptr;
+}
+
 void
 nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify,
                          nsIContent* aKid, nsAttrAndChildArray& aChildArray)
 {
   NS_PRECONDITION(aKid && aKid->GetParentNode() == this &&
                   aKid == GetChildAt(aIndex) &&
                   IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid");
 
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -244,16 +244,17 @@ MOCHITEST_FILES_A = \
 		test_bug282547.html \
 		bug282547.sjs \
 		test_domparser_null_char.html \
 		test_bug811701.html \
 		test_bug811701.xhtml \
 		test_bug820909.html \
 		test_bug704063.html \
 		test_bug894874.html \
+		test_bug895974.html \
 		$(NULL)
 
 MOCHITEST_FILES_B = \
 		test_bug459424.html \
 		bug461735-redirect1.sjs \
 		bug461735-redirect2.sjs \
 		bug461735-post-redirect.js \
 		test_bug513194.html \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug895974.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=895974
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 895974</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 895974 **/
+  SimpleTest.waitForExplicitFinish();
+
+  addLoadEvent(function() {
+  var frag = document.createDocumentFragment();
+  var span = document.createElement("span");
+  var div = document.createElement("div");
+  var text = document.createTextNode("help");
+  frag.appendChild(document.createTextNode("fail"));
+  frag.appendChild(span);
+  frag.appendChild(text);
+  frag.appendChild(div);
+  frag.appendChild(document.createTextNode("fail"));
+
+  is(text.nextElementSibling, div, "nextElementSibling should work on text");
+  is(text.previousElementSibling, span,
+    "previousElementSibling should work on text");
+
+  is(document.firstElementChild, document.documentElement,
+     "firstElementChild should work on document");
+  is(document.lastElementChild, document.documentElement,
+     "lastElementChild should work on document");
+  is(document.children.length, 1, "Document has one element kid");
+  is(document.children[0], document.documentElement,
+     "Document only element child is <html>");
+
+  is(frag.firstElementChild, span,
+     "firstElementChild should work on document fragment");
+  is(frag.lastElementChild, div,
+     "lastElementChild should work on document fragment");
+  is(frag.children.length, 2, "Document fragment has two element kids");
+  is(frag.children[0], span, "Document fragment first element child is span");
+  is(frag.children[1], div, "Document fragment second element child is div");
+
+  is(document.documentElement.firstElementChild, document.head,
+     "firstElementChild should work on element");
+  is(document.documentElement.lastElementChild, document.body,
+     "lastElementChild should work on element");
+  is(document.documentElement.children.length, 2, "<html> has two element kids");
+  is(document.documentElement.children[0], document.head,
+     "<html> first element child is head");
+  is(document.documentElement.children[1], document.body,
+     "<html>  second element child is body");
+  SimpleTest.finish();
+  });
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=895974">Mozilla Bug 895974</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/webidl/ChildNode.webidl
+++ b/dom/webidl/ChildNode.webidl
@@ -4,18 +4,19 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://dom.spec.whatwg.org/#interface-childnode
  */
 
 [NoInterfaceObject]
 interface ChildNode {
-// On Element:
-//  readonly attribute Element? previousElementSibling;
-//  readonly attribute Element? nextElementSibling;
+  [Pure]
+  readonly attribute Element? previousElementSibling;
+  [Pure]
+  readonly attribute Element? nextElementSibling;
 
 // Not implemented yet:
 //  void before((Node or DOMString)... nodes);
 //  void after((Node or DOMString)... nodes);
 //  void replace((Node or DOMString)... nodes);
   void remove();
 };
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -329,8 +329,9 @@ partial interface Document {
 partial interface Document {
   [ChromeOnly] readonly attribute boolean isSrcdocDocument;
 };
 
 Document implements XPathEvaluator;
 Document implements GlobalEventHandlers;
 Document implements NodeEventHandlers;
 Document implements TouchEventHandlers;
+Document implements ParentNode;
--- a/dom/webidl/DocumentFragment.webidl
+++ b/dom/webidl/DocumentFragment.webidl
@@ -24,8 +24,10 @@ interface DocumentFragment : Node {
 
 // http://www.w3.org/TR/2012/WD-selectors-api-20120628/#interface-definitions
 partial interface DocumentFragment {
   [Throws]
   Element?  querySelector(DOMString selectors);
   [Throws]
   NodeList  querySelectorAll(DOMString selectors);
 };
+
+DocumentFragment implements ParentNode;
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -50,29 +50,16 @@ interface Element : Node {
   boolean hasAttribute(DOMString name);
   boolean hasAttributeNS(DOMString? namespace, DOMString localName);
 
   HTMLCollection getElementsByTagName(DOMString localName);
   [Throws]
   HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
   HTMLCollection getElementsByClassName(DOMString classNames);
 
-  [Constant]
-  readonly attribute HTMLCollection children;
-  [Pure]
-  readonly attribute Element? firstElementChild;
-  [Pure]
-  readonly attribute Element? lastElementChild;
-  [Pure]
-  readonly attribute Element? previousElementSibling;
-  [Pure]
-  readonly attribute Element? nextElementSibling;
-  [Pure]
-  readonly attribute unsigned long childElementCount;
-
   /**
    * The ratio of font-size-inflated text font size to computed font
    * size for this element. This will query the element for its primary frame,
    * and then use this to get font size inflation information about the frame.
    * This will be 1.0 if font size inflation is not enabled, and -1.0 if an
    * error occurred during the retrieval of the font size inflation.
    *
    * @note The font size inflation ratio that is returned is actually the
@@ -194,8 +181,9 @@ partial interface Element {
 partial interface Element {
   [Throws]
   Element?  querySelector(DOMString selectors);
   [Throws]
   NodeList  querySelectorAll(DOMString selectors);
 };
 
 Element implements ChildNode;
+Element implements ParentNode;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ParentNode.webidl
@@ -0,0 +1,24 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * The origin of this IDL file is
+ * http://dom.spec.whatwg.org/#interface-parentnode
+ */
+
+[NoInterfaceObject]
+interface ParentNode {
+  [Constant]
+  readonly attribute HTMLCollection children;
+  [Pure]
+  readonly attribute Element? firstElementChild;
+  [Pure]
+  readonly attribute Element? lastElementChild;
+  [Pure]
+  readonly attribute unsigned long childElementCount;
+
+  // Not implemented yet
+  // void prepend((Node or DOMString)... nodes);
+  // void append((Node or DOMString)... nodes);
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -204,16 +204,17 @@ webidl_files = \
   NotifyAudioAvailableEvent.webidl \
   NotifyPaintEvent.webidl \
   OfflineAudioCompletionEvent.webidl \
   OfflineAudioContext.webidl \
   OfflineResourceList.webidl \
   PaintRequest.webidl \
   PaintRequestList.webidl \
   PannerNode.webidl \
+  ParentNode.webidl \
   Performance.webidl \
   PerformanceNavigation.webidl \
   PerformanceTiming.webidl \
   PeriodicWave.webidl \
   Plugin.webidl \
   PluginArray.webidl \
   Position.webidl \
   PositionError.webidl \