Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Unified Diff: third_party/WebKit/Source/core/dom/DOMTokenList.cpp

Issue 2895903002: DOMTokenList: Update serialization algorithm on add()/remove() (Closed)
Patch Set: Apply review comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/dom/DOMTokenList.cpp
diff --git a/third_party/WebKit/Source/core/dom/DOMTokenList.cpp b/third_party/WebKit/Source/core/dom/DOMTokenList.cpp
index 1446659eac750382785f954e679268238a4d7bc6..47b0cc1e4cf920cf5312b47834f280ddac4bc45c 100644
--- a/third_party/WebKit/Source/core/dom/DOMTokenList.cpp
+++ b/third_party/WebKit/Source/core/dom/DOMTokenList.cpp
@@ -31,14 +31,22 @@
namespace blink {
+// This implements the common part of the following operations:
+// https://dom.spec.whatwg.org/#dom-domtokenlist-add
+// https://dom.spec.whatwg.org/#dom-domtokenlist-remove
+// https://dom.spec.whatwg.org/#dom-domtokenlist-toggle
+// https://dom.spec.whatwg.org/#dom-domtokenlist-replace
bool DOMTokenList::ValidateToken(const String& token,
ExceptionState& exception_state) const {
+ // 1. If token is the empty string, then throw a SyntaxError.
if (token.IsEmpty()) {
exception_state.ThrowDOMException(kSyntaxError,
"The token provided must not be empty.");
return false;
}
+ // 2. If token contains any ASCII whitespace, then throw an
+ // InvalidCharacterError.
if (token.Find(IsHTMLSpace) != kNotFound) {
exception_state.ThrowDOMException(kInvalidCharacterError,
"The token provided ('" + token +
@@ -79,24 +87,15 @@ void DOMTokenList::add(const AtomicString& token,
add(tokens, exception_state);
}
+// https://dom.spec.whatwg.org/#dom-domtokenlist-add
// Optimally, this should take a Vector<AtomicString> const ref in argument but
// the bindings generator does not handle that.
void DOMTokenList::add(const Vector<String>& tokens,
ExceptionState& exception_state) {
- Vector<String> filtered_tokens;
- filtered_tokens.ReserveCapacity(tokens.size());
- for (const auto& token : tokens) {
- if (!ValidateToken(token, exception_state))
- return;
- if (ContainsInternal(AtomicString(token)))
- continue;
- if (filtered_tokens.Contains(token))
- continue;
- filtered_tokens.push_back(token);
- }
+ if (!ValidateTokens(tokens, exception_state))
+ return;
- if (!filtered_tokens.IsEmpty())
- setValue(AddTokens(value(), filtered_tokens));
+ setValue(AddTokens(tokens));
}
void DOMTokenList::remove(const AtomicString& token,
@@ -106,6 +105,7 @@ void DOMTokenList::remove(const AtomicString& token,
remove(tokens, exception_state);
}
+// https://dom.spec.whatwg.org/#dom-domtokenlist-remove
// Optimally, this should take a Vector<AtomicString> const ref in argument but
// the bindings generator does not handle that.
void DOMTokenList::remove(const Vector<String>& tokens,
@@ -113,17 +113,11 @@ void DOMTokenList::remove(const Vector<String>& tokens,
if (!ValidateTokens(tokens, exception_state))
return;
- // Check using containsInternal first since it is a lot faster than going
- // through the string character by character.
- bool found = false;
- for (const auto& token : tokens) {
- if (ContainsInternal(AtomicString(token))) {
- found = true;
- break;
- }
- }
-
- setValue(found ? RemoveTokens(value(), tokens) : value());
+ // TODO(tkent): This null check doesn't conform to the DOM specification.
+ // See https://github.com/whatwg/dom/issues/462
+ if (value().IsNull())
+ return;
+ setValue(RemoveTokens(tokens));
}
bool DOMTokenList::toggle(const AtomicString& token,
@@ -160,7 +154,7 @@ bool DOMTokenList::supports(const AtomicString& token,
void DOMTokenList::AddInternal(const AtomicString& token) {
if (!ContainsInternal(token))
- setValue(AddToken(value(), token));
+ setValue(AddToken(token));
}
void DOMTokenList::RemoveInternal(const AtomicString& token) {
@@ -168,95 +162,62 @@ void DOMTokenList::RemoveInternal(const AtomicString& token) {
// of character by character testing.
if (!ContainsInternal(token))
return;
- setValue(RemoveToken(value(), token));
+ setValue(RemoveToken(token));
}
-AtomicString DOMTokenList::AddToken(const AtomicString& input,
- const AtomicString& token) {
+AtomicString DOMTokenList::AddToken(const AtomicString& token) {
Vector<String> tokens;
tokens.push_back(token.GetString());
- return AddTokens(input, tokens);
+ return AddTokens(tokens);
}
+// https://dom.spec.whatwg.org/#dom-domtokenlist-add
// This returns an AtomicString because it is always passed as argument to
// setValue() and setValue() takes an AtomicString in argument.
-AtomicString DOMTokenList::AddTokens(const AtomicString& input,
- const Vector<String>& tokens) {
- bool needs_space = false;
-
- StringBuilder builder;
- if (!input.IsEmpty()) {
- builder.Append(input);
- needs_space = !IsHTMLSpace<UChar>(input[input.length() - 1]);
- }
-
- for (const auto& token : tokens) {
- if (needs_space)
- builder.Append(' ');
- builder.Append(token);
- needs_space = true;
- }
-
- return builder.ToAtomicString();
+AtomicString DOMTokenList::AddTokens(const Vector<String>& tokens) {
+ SpaceSplitString& token_set = MutableSet();
+ // 2. For each token in tokens, append token to context object’s token set.
+ for (const auto& token : tokens)
+ token_set.Add(AtomicString(token));
+ // 3. Run the update steps.
+ return SerializeSet(token_set);
}
-AtomicString DOMTokenList::RemoveToken(const AtomicString& input,
- const AtomicString& token) {
+AtomicString DOMTokenList::RemoveToken(const AtomicString& token) {
Vector<String> tokens;
tokens.push_back(token.GetString());
- return RemoveTokens(input, tokens);
+ return RemoveTokens(tokens);
}
+// https://dom.spec.whatwg.org/#dom-domtokenlist-remove
// This returns an AtomicString because it is always passed as argument to
// setValue() and setValue() takes an AtomicString in argument.
-AtomicString DOMTokenList::RemoveTokens(const AtomicString& input,
- const Vector<String>& tokens) {
- // Algorithm defined at
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#remove-a-token-from-a-string
- // New spec is at https://dom.spec.whatwg.org/#remove-a-token-from-a-string
-
- unsigned input_length = input.length();
- StringBuilder output; // 3
- output.ReserveCapacity(input_length);
- unsigned position = 0; // 4
-
- // Step 5
- while (position < input_length) {
- if (IsHTMLSpace<UChar>(input[position])) { // 6
- position++;
- continue; // 6.3
- }
-
- // Step 7
- StringBuilder token_builder;
- while (position < input_length && IsNotHTMLSpace<UChar>(input[position]))
- token_builder.Append(input[position++]);
-
- // Step 8
- String token = token_builder.ToString();
- if (tokens.Contains(token)) {
- // Step 8.1
- while (position < input_length && IsHTMLSpace<UChar>(input[position]))
- ++position;
-
- // Step 8.2
- size_t j = output.length();
- while (j > 0 && IsHTMLSpace<UChar>(output[j - 1]))
- --j;
- output.Resize(j);
- } else {
- output.Append(token); // Step 9
- }
-
- if (position < input_length && !output.IsEmpty())
- output.Append(' ');
+AtomicString DOMTokenList::RemoveTokens(const Vector<String>& tokens) {
+ SpaceSplitString& token_set = MutableSet();
+ // 2. For each token in tokens, remove token from context object’s token set.
+ for (const auto& token : tokens)
+ token_set.Remove(AtomicString(token));
+ // 3. Run the update steps.
+ return SerializeSet(token_set);
+}
+
+// https://dom.spec.whatwg.org/#concept-ordered-set-serializer
+// The ordered set serializer takes a set and returns the concatenation of the
+// strings in set, separated from each other by U+0020, if set is non-empty, and
+// the empty string otherwise.
+AtomicString DOMTokenList::SerializeSet(const SpaceSplitString& token_set) {
+ size_t size = token_set.size();
+ if (size == 0)
+ return g_empty_atom;
+ if (size == 1)
+ return token_set[0];
+ StringBuilder builder;
+ builder.Append(token_set[0]);
+ for (size_t i = 1; i < size; ++i) {
+ builder.Append(' ');
+ builder.Append(token_set[i]);
}
-
- size_t j = output.length();
- if (j > 0 && IsHTMLSpace<UChar>(output[j - 1]))
- output.Resize(j - 1);
-
- return output.ToAtomicString();
+ return builder.ToAtomicString();
}
void DOMTokenList::setValue(const AtomicString& value) {
« no previous file with comments | « third_party/WebKit/Source/core/dom/DOMTokenList.h ('k') | third_party/WebKit/Source/core/dom/SpaceSplitString.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698