Chromium Code Reviews| 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 e7d658e2a95146c7b8e8692f64b1320db8fa6b13..9c2ff7c0c1b3a8139733ed502ed5d6b36221152b 100644 |
| --- a/third_party/WebKit/Source/core/dom/DOMTokenList.cpp |
| +++ b/third_party/WebKit/Source/core/dom/DOMTokenList.cpp |
| @@ -85,20 +85,15 @@ void DOMTokenList::add(const AtomicString& token, |
| // 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); |
| - } |
| + // https://dom.spec.whatwg.org/#dom-domtokenlist-add |
| + // 1. For each token in tokens: |
| + // 1. If token is the empty string, then throw a SyntaxError. |
| + // 2. If token contains any ASCII whitespace, then throw an |
| + // InvalidCharacterError. |
|
kochi
2017/05/24 05:46:00
This comment is identical to line 111-, and the al
tkent
2017/05/24 06:05:34
Done.
|
| + if (!ValidateTokens(tokens, exception_state)) |
| + return; |
| - if (!filtered_tokens.IsEmpty()) |
| - setValue(AddTokens(value(), filtered_tokens)); |
| + setValue(AddTokens(tokens)); |
| } |
| void DOMTokenList::remove(const AtomicString& token, |
| @@ -112,20 +107,18 @@ void DOMTokenList::remove(const AtomicString& token, |
| // the bindings generator does not handle that. |
| void DOMTokenList::remove(const Vector<String>& tokens, |
| ExceptionState& exception_state) { |
| + // https://dom.spec.whatwg.org/#dom-domtokenlist-remove |
| + // 1. For each token in tokens: |
| + // 1. If token is the empty string, then throw a SyntaxError. |
| + // 2. If token contains any ASCII whitespace, then throw an |
| + // InvalidCharacterError. |
| 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()); |
| + // https://github.com/whatwg/dom/issues/462 |
|
kochi
2017/05/24 05:46:00
This comment is ambiguous - how about being more s
tkent
2017/05/24 06:05:34
Done.
|
| + if (value().IsNull()) |
| + return; |
| + setValue(RemoveTokens(tokens)); |
| } |
| bool DOMTokenList::toggle(const AtomicString& token, |
| @@ -162,7 +155,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) { |
| @@ -170,95 +163,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); |
| } |
| // 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) { |
| + // https://dom.spec.whatwg.org/#dom-domtokenlist-add |
| + 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); |
| } |
| // 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) { |
| + // https://dom.spec.whatwg.org/#dom-domtokenlist-remove |
| + 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); |
| +} |
| + |
| +AtomicString DOMTokenList::SerializeSet(const SpaceSplitString& 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. |
| + 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) { |