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

Side by Side Diff: third_party/WebKit/Source/core/dom/DOMTokenList.cpp

Issue 2895903002: DOMTokenList: Update serialization algorithm on add()/remove() (Closed)
Patch Set: Remove one -expected.txt 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 unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698