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 |