Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 78 ExceptionState& exception_state) { | 78 ExceptionState& exception_state) { |
| 79 Vector<String> tokens; | 79 Vector<String> tokens; |
| 80 tokens.push_back(token.GetString()); | 80 tokens.push_back(token.GetString()); |
| 81 add(tokens, exception_state); | 81 add(tokens, exception_state); |
| 82 } | 82 } |
| 83 | 83 |
| 84 // Optimally, this should take a Vector<AtomicString> const ref in argument but | 84 // Optimally, this should take a Vector<AtomicString> const ref in argument but |
| 85 // the bindings generator does not handle that. | 85 // the bindings generator does not handle that. |
| 86 void DOMTokenList::add(const Vector<String>& tokens, | 86 void DOMTokenList::add(const Vector<String>& tokens, |
| 87 ExceptionState& exception_state) { | 87 ExceptionState& exception_state) { |
| 88 Vector<String> filtered_tokens; | 88 // https://dom.spec.whatwg.org/#dom-domtokenlist-add |
| 89 filtered_tokens.ReserveCapacity(tokens.size()); | 89 // 1. For each token in tokens: |
| 90 for (const auto& token : tokens) { | 90 // 1. If token is the empty string, then throw a SyntaxError. |
| 91 if (!ValidateToken(token, exception_state)) | 91 // 2. If token contains any ASCII whitespace, then throw an |
| 92 return; | 92 // 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.
| |
| 93 if (ContainsInternal(AtomicString(token))) | 93 if (!ValidateTokens(tokens, exception_state)) |
| 94 continue; | 94 return; |
| 95 if (filtered_tokens.Contains(token)) | |
| 96 continue; | |
| 97 filtered_tokens.push_back(token); | |
| 98 } | |
| 99 | 95 |
| 100 if (!filtered_tokens.IsEmpty()) | 96 setValue(AddTokens(tokens)); |
| 101 setValue(AddTokens(value(), filtered_tokens)); | |
| 102 } | 97 } |
| 103 | 98 |
| 104 void DOMTokenList::remove(const AtomicString& token, | 99 void DOMTokenList::remove(const AtomicString& token, |
| 105 ExceptionState& exception_state) { | 100 ExceptionState& exception_state) { |
| 106 Vector<String> tokens; | 101 Vector<String> tokens; |
| 107 tokens.push_back(token.GetString()); | 102 tokens.push_back(token.GetString()); |
| 108 remove(tokens, exception_state); | 103 remove(tokens, exception_state); |
| 109 } | 104 } |
| 110 | 105 |
| 111 // Optimally, this should take a Vector<AtomicString> const ref in argument but | 106 // Optimally, this should take a Vector<AtomicString> const ref in argument but |
| 112 // the bindings generator does not handle that. | 107 // the bindings generator does not handle that. |
| 113 void DOMTokenList::remove(const Vector<String>& tokens, | 108 void DOMTokenList::remove(const Vector<String>& tokens, |
| 114 ExceptionState& exception_state) { | 109 ExceptionState& exception_state) { |
| 110 // https://dom.spec.whatwg.org/#dom-domtokenlist-remove | |
| 111 // 1. For each token in tokens: | |
| 112 // 1. If token is the empty string, then throw a SyntaxError. | |
| 113 // 2. If token contains any ASCII whitespace, then throw an | |
| 114 // InvalidCharacterError. | |
| 115 if (!ValidateTokens(tokens, exception_state)) | 115 if (!ValidateTokens(tokens, exception_state)) |
| 116 return; | 116 return; |
| 117 | 117 |
| 118 // Check using containsInternal first since it is a lot faster than going | 118 // 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.
| |
| 119 // through the string character by character. | 119 if (value().IsNull()) |
| 120 bool found = false; | 120 return; |
| 121 for (const auto& token : tokens) { | 121 setValue(RemoveTokens(tokens)); |
| 122 if (ContainsInternal(AtomicString(token))) { | |
| 123 found = true; | |
| 124 break; | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 setValue(found ? RemoveTokens(value(), tokens) : value()); | |
| 129 } | 122 } |
| 130 | 123 |
| 131 bool DOMTokenList::toggle(const AtomicString& token, | 124 bool DOMTokenList::toggle(const AtomicString& token, |
| 132 ExceptionState& exception_state) { | 125 ExceptionState& exception_state) { |
| 133 if (!ValidateToken(token, exception_state)) | 126 if (!ValidateToken(token, exception_state)) |
| 134 return false; | 127 return false; |
| 135 | 128 |
| 136 if (ContainsInternal(token)) { | 129 if (ContainsInternal(token)) { |
| 137 RemoveInternal(token); | 130 RemoveInternal(token); |
| 138 return false; | 131 return false; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 155 return force; | 148 return force; |
| 156 } | 149 } |
| 157 | 150 |
| 158 bool DOMTokenList::supports(const AtomicString& token, | 151 bool DOMTokenList::supports(const AtomicString& token, |
| 159 ExceptionState& exception_state) { | 152 ExceptionState& exception_state) { |
| 160 return ValidateTokenValue(token, exception_state); | 153 return ValidateTokenValue(token, exception_state); |
| 161 } | 154 } |
| 162 | 155 |
| 163 void DOMTokenList::AddInternal(const AtomicString& token) { | 156 void DOMTokenList::AddInternal(const AtomicString& token) { |
| 164 if (!ContainsInternal(token)) | 157 if (!ContainsInternal(token)) |
| 165 setValue(AddToken(value(), token)); | 158 setValue(AddToken(token)); |
| 166 } | 159 } |
| 167 | 160 |
| 168 void DOMTokenList::RemoveInternal(const AtomicString& token) { | 161 void DOMTokenList::RemoveInternal(const AtomicString& token) { |
| 169 // Check using contains first since it uses AtomicString comparisons instead | 162 // Check using contains first since it uses AtomicString comparisons instead |
| 170 // of character by character testing. | 163 // of character by character testing. |
| 171 if (!ContainsInternal(token)) | 164 if (!ContainsInternal(token)) |
| 172 return; | 165 return; |
| 173 setValue(RemoveToken(value(), token)); | 166 setValue(RemoveToken(token)); |
| 174 } | 167 } |
| 175 | 168 |
| 176 AtomicString DOMTokenList::AddToken(const AtomicString& input, | 169 AtomicString DOMTokenList::AddToken(const AtomicString& token) { |
| 177 const AtomicString& token) { | |
| 178 Vector<String> tokens; | 170 Vector<String> tokens; |
| 179 tokens.push_back(token.GetString()); | 171 tokens.push_back(token.GetString()); |
| 180 return AddTokens(input, tokens); | 172 return AddTokens(tokens); |
| 181 } | 173 } |
| 182 | 174 |
| 183 // This returns an AtomicString because it is always passed as argument to | 175 // This returns an AtomicString because it is always passed as argument to |
| 184 // setValue() and setValue() takes an AtomicString in argument. | 176 // setValue() and setValue() takes an AtomicString in argument. |
| 185 AtomicString DOMTokenList::AddTokens(const AtomicString& input, | 177 AtomicString DOMTokenList::AddTokens(const Vector<String>& tokens) { |
| 186 const Vector<String>& tokens) { | 178 // https://dom.spec.whatwg.org/#dom-domtokenlist-add |
| 187 bool needs_space = false; | 179 SpaceSplitString& token_set = MutableSet(); |
| 188 | 180 // 2. For each token in tokens, append token to context object’s token set. |
| 189 StringBuilder builder; | 181 for (const auto& token : tokens) |
| 190 if (!input.IsEmpty()) { | 182 token_set.Add(AtomicString(token)); |
| 191 builder.Append(input); | 183 // 3. Run the update steps. |
| 192 needs_space = !IsHTMLSpace<UChar>(input[input.length() - 1]); | 184 return SerializeSet(token_set); |
| 193 } | |
| 194 | |
| 195 for (const auto& token : tokens) { | |
| 196 if (needs_space) | |
| 197 builder.Append(' '); | |
| 198 builder.Append(token); | |
| 199 needs_space = true; | |
| 200 } | |
| 201 | |
| 202 return builder.ToAtomicString(); | |
| 203 } | 185 } |
| 204 | 186 |
| 205 AtomicString DOMTokenList::RemoveToken(const AtomicString& input, | 187 AtomicString DOMTokenList::RemoveToken(const AtomicString& token) { |
| 206 const AtomicString& token) { | |
| 207 Vector<String> tokens; | 188 Vector<String> tokens; |
| 208 tokens.push_back(token.GetString()); | 189 tokens.push_back(token.GetString()); |
| 209 return RemoveTokens(input, tokens); | 190 return RemoveTokens(tokens); |
| 210 } | 191 } |
| 211 | 192 |
| 212 // This returns an AtomicString because it is always passed as argument to | 193 // This returns an AtomicString because it is always passed as argument to |
| 213 // setValue() and setValue() takes an AtomicString in argument. | 194 // setValue() and setValue() takes an AtomicString in argument. |
| 214 AtomicString DOMTokenList::RemoveTokens(const AtomicString& input, | 195 AtomicString DOMTokenList::RemoveTokens(const Vector<String>& tokens) { |
| 215 const Vector<String>& tokens) { | 196 // https://dom.spec.whatwg.org/#dom-domtokenlist-remove |
| 216 // Algorithm defined at | 197 SpaceSplitString& token_set = MutableSet(); |
| 217 // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyn taxes.html#remove-a-token-from-a-string | 198 // 2. For each token in tokens, remove token from context object’s token set. |
| 218 // New spec is at https://dom.spec.whatwg.org/#remove-a-token-from-a-string | 199 for (const auto& token : tokens) |
| 200 token_set.Remove(AtomicString(token)); | |
| 201 // 3. Run the update steps. | |
| 202 return SerializeSet(token_set); | |
| 203 } | |
| 219 | 204 |
| 220 unsigned input_length = input.length(); | 205 AtomicString DOMTokenList::SerializeSet(const SpaceSplitString& token_set) { |
| 221 StringBuilder output; // 3 | 206 // https://dom.spec.whatwg.org/#concept-ordered-set-serializer |
| 222 output.ReserveCapacity(input_length); | 207 // The ordered set serializer takes a set and returns the concatenation of the |
| 223 unsigned position = 0; // 4 | 208 // strings in set, separated from each other by U+0020, if set is non-empty, |
| 224 | 209 // and the empty string otherwise. |
| 225 // Step 5 | 210 size_t size = token_set.size(); |
| 226 while (position < input_length) { | 211 if (size == 0) |
| 227 if (IsHTMLSpace<UChar>(input[position])) { // 6 | 212 return g_empty_atom; |
| 228 position++; | 213 if (size == 1) |
| 229 continue; // 6.3 | 214 return token_set[0]; |
| 230 } | 215 StringBuilder builder; |
| 231 | 216 builder.Append(token_set[0]); |
| 232 // Step 7 | 217 for (size_t i = 1; i < size; ++i) { |
| 233 StringBuilder token_builder; | 218 builder.Append(' '); |
| 234 while (position < input_length && IsNotHTMLSpace<UChar>(input[position])) | 219 builder.Append(token_set[i]); |
| 235 token_builder.Append(input[position++]); | |
| 236 | |
| 237 // Step 8 | |
| 238 String token = token_builder.ToString(); | |
| 239 if (tokens.Contains(token)) { | |
| 240 // Step 8.1 | |
| 241 while (position < input_length && IsHTMLSpace<UChar>(input[position])) | |
| 242 ++position; | |
| 243 | |
| 244 // Step 8.2 | |
| 245 size_t j = output.length(); | |
| 246 while (j > 0 && IsHTMLSpace<UChar>(output[j - 1])) | |
| 247 --j; | |
| 248 output.Resize(j); | |
| 249 } else { | |
| 250 output.Append(token); // Step 9 | |
| 251 } | |
| 252 | |
| 253 if (position < input_length && !output.IsEmpty()) | |
| 254 output.Append(' '); | |
| 255 } | 220 } |
| 256 | 221 return builder.ToAtomicString(); |
| 257 size_t j = output.length(); | |
| 258 if (j > 0 && IsHTMLSpace<UChar>(output[j - 1])) | |
| 259 output.Resize(j - 1); | |
| 260 | |
| 261 return output.ToAtomicString(); | |
| 262 } | 222 } |
| 263 | 223 |
| 264 void DOMTokenList::setValue(const AtomicString& value) { | 224 void DOMTokenList::setValue(const AtomicString& value) { |
| 265 bool value_changed = value_ != value; | 225 bool value_changed = value_ != value; |
| 266 value_ = value; | 226 value_ = value; |
| 267 if (value_changed) | 227 if (value_changed) |
| 268 tokens_.Set(value, SpaceSplitString::kShouldNotFoldCase); | 228 tokens_.Set(value, SpaceSplitString::kShouldNotFoldCase); |
| 269 if (observer_) | 229 if (observer_) |
| 270 observer_->ValueWasSet(); | 230 observer_->ValueWasSet(); |
| 271 } | 231 } |
| 272 | 232 |
| 273 bool DOMTokenList::ContainsInternal(const AtomicString& token) const { | 233 bool DOMTokenList::ContainsInternal(const AtomicString& token) const { |
| 274 return tokens_.Contains(token); | 234 return tokens_.Contains(token); |
| 275 } | 235 } |
| 276 | 236 |
| 277 const AtomicString DOMTokenList::item(unsigned index) const { | 237 const AtomicString DOMTokenList::item(unsigned index) const { |
| 278 if (index >= length()) | 238 if (index >= length()) |
| 279 return AtomicString(); | 239 return AtomicString(); |
| 280 return tokens_[index]; | 240 return tokens_[index]; |
| 281 } | 241 } |
| 282 | 242 |
| 283 } // namespace blink | 243 } // namespace blink |
| OLD | NEW |