Bug 1293563: Fix some DOMTokenList.replace bugs. r=baku
authorEmilio Cobos Álvarez <ecoal95@gmail.com>
Mon, 08 Aug 2016 22:48:30 -0700
changeset 352795 3faaecb8dfcbc05a7b65ac9f0ff11955ec1b4829
parent 352794 29179e545070ca6ead649caaa4d4690c1ec3046e
child 352796 e8ada2555f8372df966719bb42f32bf5cbe93761
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1293563
milestone51.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 1293563: Fix some DOMTokenList.replace bugs. r=baku MozReview-Commit-ID: C2tCbHmwsi6
dom/base/nsDOMTokenList.cpp
dom/base/nsDOMTokenList.h
testing/web-platform/meta/dom/nodes/Element-classlist.html.ini
--- a/dom/base/nsDOMTokenList.cpp
+++ b/dom/base/nsDOMTokenList.cpp
@@ -9,16 +9,17 @@
  */
 
 #include "nsDOMTokenList.h"
 #include "nsAttrValue.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/DOMTokenListBinding.h"
+#include "nsWhitespaceTokenizer.h"
 #include "mozilla/ErrorResult.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsDOMTokenList::nsDOMTokenList(Element* aElement, nsIAtom* aAttrAtom,
                                const DOMTokenListSupportedTokenArray aSupportedTokens)
   : mElement(aElement),
@@ -324,27 +325,58 @@ nsDOMTokenList::Replace(const nsAString&
   }
 
   aError = CheckToken(aNewToken);
   if (aError.Failed()) {
     return;
   }
 
   const nsAttrValue* attr = GetParsedAttr();
-  if (!attr || !attr->Contains(aToken)) {
+  if (!attr) {
     return;
   }
 
-  AutoTArray<nsString, 1> tokens;
+  ReplaceInternal(attr, aToken, aNewToken);
+}
+
+void
+nsDOMTokenList::ReplaceInternal(const nsAttrValue* aAttr,
+                                const nsAString& aToken,
+                                const nsAString& aNewToken)
+{
+  nsAutoString attribute;
+  aAttr->ToString(attribute);
+
+  nsAutoString result;
+
+  nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace>
+    tokenizer(attribute);
 
-  tokens.AppendElement(aToken);
-  RemoveInternal(attr, tokens);
+  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);
+      }
+    } else {
+      if (!result.IsEmpty()) {
+        result.Append(char16_t(' '));
+      }
+      result.Append(currentToken);
+    }
+  }
 
-  tokens[0] = aNewToken;
-  AddInternal(attr, tokens);
+  if (sawIt) {
+    mElement->SetAttr(kNameSpaceID_None, mAttrAtom, result, true);
+  }
 }
 
 bool
 nsDOMTokenList::Supports(const nsAString& aToken,
                          ErrorResult& aError)
 {
   if (!mSupportedTokens) {
     aError.ThrowTypeError<MSG_TOKENLIST_NO_SUPPORTED_TOKENS>(
--- a/dom/base/nsDOMTokenList.h
+++ b/dom/base/nsDOMTokenList.h
@@ -82,16 +82,19 @@ protected:
   virtual ~nsDOMTokenList();
 
   nsresult CheckToken(const nsAString& aStr);
   nsresult CheckTokens(const nsTArray<nsString>& aStr);
   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();
 
   nsCOMPtr<Element> mElement;
   nsCOMPtr<nsIAtom> mAttrAtom;
   const mozilla::dom::DOMTokenListSupportedTokenArray mSupportedTokens;
 };
 
 #endif // nsDOMTokenList_h___
--- a/testing/web-platform/meta/dom/nodes/Element-classlist.html.ini
+++ b/testing/web-platform/meta/dom/nodes/Element-classlist.html.ini
@@ -22,23 +22,10 @@
     expected: FAIL
 
   [classList.add should treat \\n as a space]
     expected: FAIL
 
   [classList.add should treat \\f as a space]
     expected: FAIL
 
-  [classList.replace must replace existing tokens]
-    expected: FAIL
-
-  [classList.replace must collapse whitespace around replaced tokens]
-    expected: FAIL
-
-  [classList.replace must collapse whitespaces around each token]
-    expected: FAIL
-
   [classList.replace must collapse whitespaces around each token and remove duplicates]
     expected: FAIL
-
-  [classList.replace must collapse whitespace when replacing duplicate tokens]
-    expected: FAIL
-