Bug 869788 - Normalize DOMTokenList for whitespace/dupes; r?smaug draft
authorAryeh Gregor <ayg@aryeh.name>
Mon, 11 Apr 2016 18:01:14 +0300
changeset 567282 3a2de8bfacd0b312bc7dee544d242fde35ae3dea
parent 567252 62a2d3693579fc77b1c510984ae471a860d03302
child 625593 424b35a6e569edc5981662e8d7d9a493d919b494
push id55515
push userbmo:ayg@aryeh.name
push dateMon, 24 Apr 2017 18:09:41 +0000
reviewerssmaug
bugs869788
milestone55.0a1
Bug 869788 - Normalize DOMTokenList for whitespace/dupes; r?smaug Some bits taken from a patch by Cameron McCormack. This follows a change to the DOM spec that has already been implemented by WebKit. We do no checks for duplicates on initial attribute parsing, only when the DOMTokenList is accessed. We re-check for duplicates on every DOMTokenList access, but optimized with a bloom filter, so it should be fast. It would be possible to add a flag to check if we've already removed duplicates from the atom list, but it would require the nsAttrValue to talk to the nsDOMTokenList somehow, and a spare bit would be needed in nsAttrValue, and it would only help cases where DOMTokenList is repeatedly accessed without the content attribute being modified in between (e.g., .length) where the token list is extremely long. This patch assumes that no one other than nsDOMTokenList cares if duplicates are removed from the nsAttrValue's atom array. If anything does, they will see inconsistent behavior depending on whether nsDOMTokenList has removed duplicates yet. Since we don't want to check for duplicates on parse for performance reasons, the correct fix is to update the code elsewhere to also remove duplicates. MozReview-Commit-ID: 97KRVhPGwm8
dom/base/nsDOMTokenList.cpp
dom/base/nsDOMTokenList.h
testing/web-platform/meta/dom/lists/DOMTokenList-Iterable.html.ini
testing/web-platform/meta/dom/lists/DOMTokenList-iteration.html.ini
testing/web-platform/meta/dom/lists/DOMTokenList-value.html.ini
testing/web-platform/meta/dom/nodes/Element-classlist.html.ini
testing/web-platform/mozilla/meta/dom/classList.html.ini
--- a/dom/base/nsDOMTokenList.cpp
+++ b/dom/base/nsDOMTokenList.cpp
@@ -5,19 +5,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * Implementation of DOMTokenList specified by HTML5.
  */
 
 #include "nsDOMTokenList.h"
 #include "nsAttrValue.h"
+#include "nsAttrValueInlines.h"
+#include "nsDataHashtable.h"
 #include "nsError.h"
+#include "nsHashKeys.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/DOMTokenListBinding.h"
+#include "mozilla/BloomFilter.h"
 #include "mozilla/ErrorResult.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsDOMTokenList::nsDOMTokenList(Element* aElement, nsIAtom* aAttrAtom,
                                const DOMTokenListSupportedTokenArray aSupportedTokens)
   : mElement(aElement),
@@ -45,32 +49,79 @@ const nsAttrValue*
 nsDOMTokenList::GetParsedAttr()
 {
   if (!mElement) {
     return nullptr;
   }
   return mElement->GetAttrInfo(kNameSpaceID_None, mAttrAtom).mValue;
 }
 
+void
+nsDOMTokenList::RemoveDuplicates(const nsAttrValue* aAttr)
+{
+  if (!aAttr || aAttr->Type() != nsAttrValue::eAtomArray) {
+    return;
+  }
+
+  BloomFilter<8, nsIAtom> filter;
+  nsAttrValue::AtomArray* array = aAttr->GetAtomArrayValue();
+  for (uint32_t i = 0; i < array->Length(); i++) {
+    nsIAtom* atom = array->ElementAt(i);
+    if (filter.mightContain(atom)) {
+      // Start again, with a hashtable
+      RemoveDuplicatesInternal(array, i);
+      return;
+    } else {
+      filter.add(atom);
+    }
+  }
+}
+
+void
+nsDOMTokenList::RemoveDuplicatesInternal(nsAttrValue::AtomArray* aArray,
+                                         uint32_t aStart)
+{
+  nsDataHashtable<nsPtrHashKey<nsIAtom>, bool> tokens;
+
+  for (uint32_t i = 0; i < aArray->Length(); i++) {
+    nsIAtom* atom = aArray->ElementAt(i);
+    // No need to check the hashtable below aStart
+    if (i >= aStart && tokens.Get(atom)) {
+      aArray->RemoveElementAt(i);
+      i--;
+    } else {
+      tokens.Put(atom, true);
+    }
+  }
+}
+
 uint32_t
 nsDOMTokenList::Length()
 {
   const nsAttrValue* attr = GetParsedAttr();
   if (!attr) {
     return 0;
   }
 
+  RemoveDuplicates(attr);
   return attr->GetAtomCount();
 }
 
 void
 nsDOMTokenList::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aResult)
 {
   const nsAttrValue* attr = GetParsedAttr();
 
+  if (!attr || aIndex >= static_cast<uint32_t>(attr->GetAtomCount())) {
+    aFound = false;
+    return;
+  }
+
+  RemoveDuplicates(attr);
+
   if (attr && aIndex < static_cast<uint32_t>(attr->GetAtomCount())) {
     aFound = true;
     attr->AtomAt(aIndex)->ToString(aResult);
   } else {
     aFound = false;
   }
 }
 
@@ -130,40 +181,40 @@ nsDOMTokenList::AddInternal(const nsAttr
 {
   if (!mElement) {
     return;
   }
 
   nsAutoString resultStr;
 
   if (aAttr) {
-    aAttr->ToString(resultStr);
+    RemoveDuplicates(aAttr);
+    for (uint32_t i = 0; i < aAttr->GetAtomCount(); i++) {
+      if (i != 0) {
+        resultStr.AppendLiteral(" ");
+      }
+      resultStr.Append(nsDependentAtomString(aAttr->AtomAt(i)));
+    }
   }
 
-  bool oneWasAdded = false;
   AutoTArray<nsString, 10> addedClasses;
 
   for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) {
     const nsString& aToken = aTokens[i];
 
     if ((aAttr && aAttr->Contains(aToken)) ||
         addedClasses.Contains(aToken)) {
       continue;
     }
 
-    if (oneWasAdded ||
-        (!resultStr.IsEmpty() &&
-        !nsContentUtils::IsHTMLWhitespace(resultStr.Last()))) {
+    if (!resultStr.IsEmpty()) {
       resultStr.Append(' ');
-      resultStr.Append(aToken);
-    } else {
-      resultStr.Append(aToken);
     }
+    resultStr.Append(aToken);
 
-    oneWasAdded = true;
     addedClasses.AppendElement(aToken);
   }
 
   mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
 }
 
 void
 nsDOMTokenList::Add(const nsTArray<nsString>& aTokens, ErrorResult& aError)
@@ -186,33 +237,30 @@ nsDOMTokenList::Add(const nsAString& aTo
 }
 
 void
 nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
                                const nsTArray<nsString>& aTokens)
 {
   MOZ_ASSERT(aAttr, "Need an attribute");
 
-  nsAutoString input;
-  aAttr->ToString(input);
-
-  WhitespaceTokenizer tokenizer(input);
-  nsAutoString output;
+  RemoveDuplicates(aAttr);
 
-  while (tokenizer.hasMoreTokens()) {
-    auto& currentToken = tokenizer.nextToken();
-    if (!aTokens.Contains(currentToken)) {
-      if (!output.IsEmpty()) {
-        output.Append(char16_t(' '));
-      }
-      output.Append(currentToken);
+  nsAutoString resultStr;
+  for (uint32_t i = 0; i < aAttr->GetAtomCount(); i++) {
+    if (aTokens.Contains(nsDependentAtomString(aAttr->AtomAt(i)))) {
+      continue;
     }
+    if (!resultStr.IsEmpty()) {
+      resultStr.AppendLiteral(" ");
+    }
+    resultStr.Append(nsDependentAtomString(aAttr->AtomAt(i)));
   }
 
-  mElement->SetAttr(kNameSpaceID_None, mAttrAtom, output, true);
+  mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
 }
 
 void
 nsDOMTokenList::Remove(const nsTArray<nsString>& aTokens, ErrorResult& aError)
 {
   aError = CheckTokens(aTokens);
   if (aError.Failed()) {
     return;
@@ -298,43 +346,42 @@ nsDOMTokenList::Replace(const nsAString&
   ReplaceInternal(attr, aToken, aNewToken);
 }
 
 void
 nsDOMTokenList::ReplaceInternal(const nsAttrValue* aAttr,
                                 const nsAString& aToken,
                                 const nsAString& aNewToken)
 {
-  nsAutoString attribute;
-  aAttr->ToString(attribute);
-
-  nsAutoString result;
-  WhitespaceTokenizer tokenizer(attribute);
+  RemoveDuplicates(aAttr);
 
   bool sawIt = false;
-  while (tokenizer.hasMoreTokens()) {
-    auto currentToken = tokenizer.nextToken();
-    if (currentToken.Equals(aToken) || currentToken.Equals(aNewToken)) {
-      if (!sawIt) {
-        sawIt = true;
-        if (!result.IsEmpty()) {
-          result.Append(char16_t(' '));
-        }
-        result.Append(aNewToken);
+  nsAutoString resultStr;
+  for (uint32_t i = 0; i < aAttr->GetAtomCount(); i++) {
+    if (aAttr->AtomAt(i)->Equals(aToken) ||
+        aAttr->AtomAt(i)->Equals(aNewToken)) {
+      if (sawIt) {
+        // We keep only the first
+        continue;
       }
-    } else {
-      if (!result.IsEmpty()) {
-        result.Append(char16_t(' '));
+      sawIt = true;
+      if (!resultStr.IsEmpty()) {
+        resultStr.AppendLiteral(" ");
       }
-      result.Append(currentToken);
+      resultStr.Append(aNewToken);
+      continue;
     }
+    if (!resultStr.IsEmpty()) {
+      resultStr.AppendLiteral(" ");
+    }
+    resultStr.Append(nsDependentAtomString(aAttr->AtomAt(i)));
   }
 
   if (sawIt) {
-    mElement->SetAttr(kNameSpaceID_None, mAttrAtom, result, true);
+    mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
   }
 }
 
 bool
 nsDOMTokenList::Supports(const nsAString& aToken,
                          ErrorResult& aError)
 {
   if (!mSupportedTokens) {
--- a/dom/base/nsDOMTokenList.h
+++ b/dom/base/nsDOMTokenList.h
@@ -47,16 +47,17 @@ public:
 
   virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
   Element* GetParentObject()
   {
     return mElement;
   }
 
+  void RemoveDuplicates(const nsAttrValue* aAttr);
   uint32_t Length();
   void Item(uint32_t aIndex, nsAString& aResult)
   {
     bool found;
     IndexedGetter(aIndex, found, aResult);
     if (!found) {
       SetDOMStringToNull(aResult);
     }
@@ -82,16 +83,18 @@ public:
   void SetValue(const nsAString& aValue, mozilla::ErrorResult& rv);
   void Stringify(nsAString& aResult);
 
 protected:
   virtual ~nsDOMTokenList();
 
   nsresult CheckToken(const nsAString& aStr);
   nsresult CheckTokens(const nsTArray<nsString>& aStr);
+  void RemoveDuplicatesInternal(nsTArray<nsCOMPtr<nsIAtom>>* aArray,
+                                uint32_t aStart);
   void AddInternal(const nsAttrValue* aAttr,
                    const nsTArray<nsString>& aTokens);
   void RemoveInternal(const nsAttrValue* aAttr,
                       const nsTArray<nsString>& aTokens);
   void ReplaceInternal(const nsAttrValue* aAttr,
                        const nsAString& aToken,
                        const nsAString& aNewToken);
   inline const nsAttrValue* GetParsedAttr();
deleted file mode 100644
--- a/testing/web-platform/meta/dom/lists/DOMTokenList-Iterable.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[DOMTokenList-Iterable.html]
-  type: testharness
-  [DOMTokenList is iterable via for-of loop.]
-    expected: FAIL
-    bug: https://github.com/whatwg/dom/issues/105
-
deleted file mode 100644
--- a/testing/web-platform/meta/dom/lists/DOMTokenList-iteration.html.ini
+++ /dev/null
@@ -1,14 +0,0 @@
-[DOMTokenList-iteration.html]
-  type: testharness
-  [DOMTokenList iteration: keys, values, etc.]
-    expected: FAIL
-
-  [classList]
-    expected: FAIL
-
-  [classList.keys]
-    expected: FAIL
-
-  [classList.values]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/dom/lists/DOMTokenList-value.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[DOMTokenList-value.html]
-  type: testharness
-  [DOMTokenList value]
-    expected: FAIL
-    bug: https://github.com/whatwg/dom/issues/105
-
deleted file mode 100644
--- a/testing/web-platform/meta/dom/nodes/Element-classlist.html.ini
+++ /dev/null
@@ -1,377 +0,0 @@
-[Element-classlist.html]
-  type: testharness
-  [classList.length when set to "a a" (HTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (HTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (HTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (HTML node)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (HTML node)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (HTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (HTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (HTML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (HTML node)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (HTML node)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (HTML node)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (HTML node)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (HTML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (HTML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a" (XHTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (XHTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (XHTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (XHTML node)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (XHTML node)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (XHTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (XHTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (XHTML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XHTML node)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (XHTML node)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (XHTML node)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (XHTML node)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XHTML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (XHTML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a" (MathML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (MathML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (MathML node)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (MathML node)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (MathML node)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (MathML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (MathML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (MathML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (MathML node)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (MathML node)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (MathML node)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (MathML node)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (MathML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (MathML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.length when set to "a a" (foo node)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (foo node)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (foo node)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (foo node)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (foo node)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (foo node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (foo node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (foo node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (foo node)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (foo node)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (foo node)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (foo node)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (foo node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (foo node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (foo node)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (foo node)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (foo node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (foo node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (foo node)]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/mozilla/meta/dom/classList.html.ini
+++ /dev/null
@@ -1,452 +0,0 @@
-[classList.html]
-  type: testharness
-  [classList.length when set to "a a" (HTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (HTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (HTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (HTML node)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (HTML node)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (HTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (HTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (HTML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (HTML node)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (HTML node)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (HTML node)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (HTML node)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (HTML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (HTML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (HTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a" (XHTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (XHTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (XHTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (XHTML node)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (XHTML node)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (XHTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (XHTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (XHTML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XHTML node)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (XHTML node)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (XHTML node)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (XHTML node)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XHTML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (XHTML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (XHTML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a" (XUL node)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (XUL node)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (XUL node)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (XUL node)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (XUL node)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (XUL node)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (XUL node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (XUL node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (XUL node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (XUL node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (XUL node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (XUL node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XUL node)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (XUL node)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (XUL node)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (XUL node)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (XUL node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (XUL node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (XUL node)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (XUL node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (XUL node)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (XUL node)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XUL node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (XUL node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (XUL node)]
-    expected: FAIL
-
-  [classList.length when set to "a a" (MathML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (MathML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (MathML node)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (MathML node)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (MathML node)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (MathML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (MathML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (MathML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (MathML node)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (MathML node)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (MathML node)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (MathML node)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (MathML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (MathML node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (MathML node)]
-    expected: FAIL
-
-  [classList.length when set to "a a" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (XML node with null namespace)]
-    expected: FAIL
-
-  [classList.length when set to "a a" (foo node)]
-    expected: FAIL
-
-  [classList.length when set to "a a a a a a" (foo node)]
-    expected: FAIL
-
-  [classList.length when set to "a a b b" (foo node)]
-    expected: FAIL
-
-  [classList.length when set to "a b c c b a a b c c" (foo node)]
-    expected: FAIL
-
-  [classList.length when set to "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.item() when set to "aa AA aa" (foo node)]
-    expected: FAIL
-
-  [classList.item() when set to "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "a a a  b" (foo node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value " " (foo node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   \\f" (foo node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.add("a") with attribute value "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (foo node)]
-    expected: FAIL
-
-  [classList.add("a", "a") with attribute value "a b c " (foo node)]
-    expected: FAIL
-
-  [classList.add() with attribute value "a b c a " (foo node)]
-    expected: FAIL
-
-  [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (foo node)]
-    expected: FAIL
-
-  [classList.remove() with attribute value "a a" (foo node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " " (foo node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value "   \\f" (foo node)]
-    expected: FAIL
-
-  [classList.toggle("d") with attribute value "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.toggle("a") with attribute value " A A A " (foo node)]
-    expected: FAIL
-
-  [classList.toggle("b") with attribute value "   a  a b" (foo node)]
-    expected: FAIL
-
-  [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (foo node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "a b a" (foo node)]
-    expected: FAIL
-
-  [classList.replace("b", "c") with attribute value "   a  a b" (foo node)]
-    expected: FAIL
-