OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "core/css/parser/MediaQueryTokenizer.h" | 6 #include "core/css/parser/MediaQueryTokenizer.h" |
7 | 7 |
8 namespace WebCore { | 8 namespace WebCore { |
9 #include "MediaQueryTokenizerCodepoints.cpp" | 9 #include "MediaQueryTokenizerCodepoints.cpp" |
10 } | 10 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
60 } | 60 } |
61 | 61 |
62 MediaQueryToken MediaQueryTokenizer::whiteSpace(UChar cc) | 62 MediaQueryToken MediaQueryTokenizer::whiteSpace(UChar cc) |
63 { | 63 { |
64 // CSS Tokenization is currently lossy, but we could record | 64 // CSS Tokenization is currently lossy, but we could record |
65 // the exact whitespace instead of discarding it here. | 65 // the exact whitespace instead of discarding it here. |
66 consumeUntilNonWhitespace(); | 66 consumeUntilNonWhitespace(); |
67 return MediaQueryToken(WhitespaceToken); | 67 return MediaQueryToken(WhitespaceToken); |
68 } | 68 } |
69 | 69 |
70 static bool popIfBlockMatches(Vector<MediaQueryTokenType>& blockStack, MediaQuer yTokenType type) | |
71 { | |
72 if (!blockStack.isEmpty() && blockStack.last() == type) { | |
73 blockStack.removeLast(); | |
74 return true; | |
75 } | |
76 return false; | |
77 } | |
78 | |
79 MediaQueryToken MediaQueryTokenizer::blockStart(MediaQueryTokenType type) | |
80 { | |
81 m_blockStack.append(type); | |
82 return MediaQueryToken(type, MediaQueryToken::BlockStart); | |
83 } | |
84 | |
85 MediaQueryToken MediaQueryTokenizer::blockStart(MediaQueryTokenType blockType, M ediaQueryTokenType type, String name) | |
86 { | |
87 m_blockStack.append(blockType); | |
88 return MediaQueryToken(type, name, MediaQueryToken::BlockStart); | |
89 } | |
90 | |
91 MediaQueryToken MediaQueryTokenizer::blockEnd(MediaQueryTokenType type, MediaQue ryTokenType startType) | |
92 { | |
93 if (popIfBlockMatches(m_blockStack, startType)) | |
94 return MediaQueryToken(type, MediaQueryToken::BlockEnd); | |
95 return MediaQueryToken(type); | |
96 } | |
97 | |
70 MediaQueryToken MediaQueryTokenizer::leftParenthesis(UChar cc) | 98 MediaQueryToken MediaQueryTokenizer::leftParenthesis(UChar cc) |
71 { | 99 { |
72 return MediaQueryToken(LeftParenthesisToken); | 100 return blockStart(LeftParenthesisToken); |
73 } | 101 } |
74 | 102 |
75 MediaQueryToken MediaQueryTokenizer::rightParenthesis(UChar cc) | 103 MediaQueryToken MediaQueryTokenizer::rightParenthesis(UChar cc) |
76 { | 104 { |
77 return MediaQueryToken(RightParenthesisToken); | 105 return blockEnd(RightParenthesisToken, LeftParenthesisToken); |
78 } | 106 } |
79 | 107 |
80 MediaQueryToken MediaQueryTokenizer::leftBracket(UChar cc) | 108 MediaQueryToken MediaQueryTokenizer::leftBracket(UChar cc) |
81 { | 109 { |
82 return MediaQueryToken(LeftBracketToken); | 110 return blockStart(LeftBracketToken); |
83 } | 111 } |
84 | 112 |
85 MediaQueryToken MediaQueryTokenizer::rightBracket(UChar cc) | 113 MediaQueryToken MediaQueryTokenizer::rightBracket(UChar cc) |
86 { | 114 { |
87 return MediaQueryToken(RightBracketToken); | 115 return blockEnd(RightBracketToken, LeftBracketToken); |
88 } | 116 } |
89 | 117 |
90 MediaQueryToken MediaQueryTokenizer::leftBrace(UChar cc) | 118 MediaQueryToken MediaQueryTokenizer::leftBrace(UChar cc) |
91 { | 119 { |
92 return MediaQueryToken(LeftBraceToken); | 120 return blockStart(LeftBraceToken); |
93 } | 121 } |
94 | 122 |
95 MediaQueryToken MediaQueryTokenizer::rightBrace(UChar cc) | 123 MediaQueryToken MediaQueryTokenizer::rightBrace(UChar cc) |
96 { | 124 { |
97 return MediaQueryToken(RightBraceToken); | 125 return blockEnd(RightBraceToken, LeftBraceToken); |
98 } | 126 } |
99 | 127 |
100 MediaQueryToken MediaQueryTokenizer::plusOrFullStop(UChar cc) | 128 MediaQueryToken MediaQueryTokenizer::plusOrFullStop(UChar cc) |
101 { | 129 { |
102 if (nextCharsAreNumber()) { | 130 if (nextCharsAreNumber()) { |
103 reconsume(cc); | 131 reconsume(cc); |
104 return consumeNumericToken(); | 132 return consumeNumericToken(); |
105 } | 133 } |
106 return MediaQueryToken(DelimiterToken, cc); | 134 return MediaQueryToken(DelimiterToken, cc); |
107 } | 135 } |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
182 // | 210 // |
183 // However, we can skip this step since: | 211 // However, we can skip this step since: |
184 // * We're using HTML spaces (which accept \r and \f as a valid white space) | 212 // * We're using HTML spaces (which accept \r and \f as a valid white space) |
185 // * Do not count white spaces | 213 // * Do not count white spaces |
186 // * consumeEscape replaces NULLs for replacement characters | 214 // * consumeEscape replaces NULLs for replacement characters |
187 | 215 |
188 MediaQueryInputStream input(string); | 216 MediaQueryInputStream input(string); |
189 MediaQueryTokenizer tokenizer(input); | 217 MediaQueryTokenizer tokenizer(input); |
190 while (true) { | 218 while (true) { |
191 MediaQueryToken token = tokenizer.nextToken(); | 219 MediaQueryToken token = tokenizer.nextToken(); |
220 token.setBlockLevel(tokenizer.m_blockStack.size()); | |
eseidel
2014/04/08 22:58:51
I see. Because the parser doesn't know how to mai
| |
192 outTokens.append(token); | 221 outTokens.append(token); |
193 if (token.type() == EOFToken) | 222 if (token.type() == EOFToken) |
194 return; | 223 return; |
195 } | 224 } |
196 } | 225 } |
197 | 226 |
198 MediaQueryToken MediaQueryTokenizer::nextToken() | 227 MediaQueryToken MediaQueryTokenizer::nextToken() |
199 { | 228 { |
200 // Unlike the HTMLTokenizer, the CSS Syntax spec is written | 229 // Unlike the HTMLTokenizer, the CSS Syntax spec is written |
201 // as a stateless, (fixed-size) look-ahead tokenizer. | 230 // as a stateless, (fixed-size) look-ahead tokenizer. |
202 // We could move to the stateful model and instead create | 231 // We could move to the stateful model and instead create |
203 // states for all the "next 3 codepoints are X" cases. | 232 // states for all the "next 3 codepoints are X" cases. |
204 // State-machine tokenizers are easier to write to handle | 233 // State-machine tokenizers are easier to write to handle |
205 // incremental tokenization of partial sources. | 234 // incremental tokenization of partial sources. |
206 // However, for now we follow the spec exactly. | 235 // However, for now we follow the spec exactly. |
207 UChar cc = consume(); | 236 UChar cc = consume(); |
208 CodePoint codePointFunc = 0; | 237 CodePoint codePointFunc = 0; |
209 | 238 |
210 if (isASCII(cc)) { | 239 if (isASCII(cc)) { |
211 ASSERT_WITH_SECURITY_IMPLICATION(cc < codePointsNumber); | 240 ASSERT_WITH_SECURITY_IMPLICATION(cc < codePointsNumber); |
212 codePointFunc = codePoints[cc]; | 241 codePointFunc = codePoints[cc]; |
213 } else { | 242 } else { |
214 codePointFunc = &MediaQueryTokenizer::nameStart; | 243 codePointFunc = &MediaQueryTokenizer::nameStart; |
215 } | 244 } |
216 | 245 |
217 if (codePointFunc) | 246 if (codePointFunc) |
218 return ((this)->*(codePointFunc))(cc); | 247 return ((this)->*(codePointFunc))(cc); |
219 | |
220 return MediaQueryToken(DelimiterToken, cc); | 248 return MediaQueryToken(DelimiterToken, cc); |
221 } | 249 } |
222 | 250 |
223 static int getSign(MediaQueryInputStream& input, unsigned& offset) | 251 static int getSign(MediaQueryInputStream& input, unsigned& offset) |
224 { | 252 { |
225 int sign = 1; | 253 int sign = 1; |
226 if (input.currentInputChar() == '+') { | 254 if (input.currentInputChar() == '+') { |
227 ++offset; | 255 ++offset; |
228 } else if (input.peek(offset) == '-') { | 256 } else if (input.peek(offset) == '-') { |
229 sign = -1; | 257 sign = -1; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
308 token.convertToDimensionWithUnit(consumeName()); | 336 token.convertToDimensionWithUnit(consumeName()); |
309 else if (consumeIfNext('%')) | 337 else if (consumeIfNext('%')) |
310 token.convertToPercentage(); | 338 token.convertToPercentage(); |
311 return token; | 339 return token; |
312 } | 340 } |
313 | 341 |
314 // http://www.w3.org/TR/css3-syntax/#consume-an-ident-like-token | 342 // http://www.w3.org/TR/css3-syntax/#consume-an-ident-like-token |
315 MediaQueryToken MediaQueryTokenizer::consumeIdentLikeToken() | 343 MediaQueryToken MediaQueryTokenizer::consumeIdentLikeToken() |
316 { | 344 { |
317 String name = consumeName(); | 345 String name = consumeName(); |
318 if (consumeIfNext('(')) | 346 if (consumeIfNext('(')) { |
319 return MediaQueryToken(FunctionToken, name); | 347 return blockStart(LeftParenthesisToken, FunctionToken, name); |
348 } | |
320 return MediaQueryToken(IdentToken, name); | 349 return MediaQueryToken(IdentToken, name); |
321 } | 350 } |
322 | 351 |
323 static bool isNewLine(UChar cc) | 352 static bool isNewLine(UChar cc) |
324 { | 353 { |
325 // We check \r and \f here, since we have no preprocessing stage | 354 // We check \r and \f here, since we have no preprocessing stage |
326 return (cc == '\r' || cc == '\n' || cc == '\f'); | 355 return (cc == '\r' || cc == '\n' || cc == '\f'); |
327 } | 356 } |
328 | 357 |
329 // http://dev.w3.org/csswg/css-syntax/#consume-a-string-token | 358 // http://dev.w3.org/csswg/css-syntax/#consume-a-string-token |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
467 if (firstChar == '-') { | 496 if (firstChar == '-') { |
468 if (isNameStart(m_input.peek(1))) | 497 if (isNameStart(m_input.peek(1))) |
469 return true; | 498 return true; |
470 return nextTwoCharsAreValidEscape(1); | 499 return nextTwoCharsAreValidEscape(1); |
471 } | 500 } |
472 | 501 |
473 return false; | 502 return false; |
474 } | 503 } |
475 | 504 |
476 } // namespace WebCore | 505 } // namespace WebCore |
OLD | NEW |