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

Side by Side Diff: Source/core/css/parser/MediaQueryParser.cpp

Issue 171383002: A thread-safe Media Query Parser (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Refactored and passes tests Created 6 years, 10 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "core/css/parser/MediaQueryParser.h"
7
8 #include "core/css/parser/BisonCSSParser.h"
9 #include "core/css/parser/MediaQueryTokenizer.h"
10
11 namespace WebCore {
12
13 PassRefPtr<MediaQuerySet> MediaQueryParser::parse(String queryString)
14 {
15 MediaQueryParser parser(queryString);
16 return parser.parseImpl();
17 }
18
19 MediaQueryParser::MediaQueryParser(String queryString)
20 : m_state(&MediaQueryParser::readRestrictor)
21 {
22 MediaQueryTokenizer::tokenize(queryString, m_tokens);
23 }
24
25 // State machine member functions start here
26 void MediaQueryParser::readRestrictor(CSSTokenType type, TokenIterator& token)
27 {
28 readMediaType(type, token);
29 }
30
31 void MediaQueryParser::readMediaType(CSSTokenType type, TokenIterator& token)
32 {
33 if (type == LeftParenToken) {
34 m_state = &MediaQueryParser::readFeature;
35 } else if (type == IdentToken) {
36 if (m_state == &MediaQueryParser::readRestrictor && token->value().lower () == "not") {
37 m_mediaQueryData.setRestrictor(MediaQuery::Not);
38 m_state = &MediaQueryParser::readMediaType;
39 } else if (m_state == &MediaQueryParser::readRestrictor && token->value( ).lower() == "only") {
40 m_mediaQueryData.setRestrictor(MediaQuery::Only);
41 m_state = &MediaQueryParser::readMediaType;
42 } else {
43 m_mediaQueryData.setMediaType(token->value());
44 m_state = &MediaQueryParser::readAnd;
45 }
46 } else if (type == EOFToken && (!m_mediaQueryData.querySetSize() || m_state != &MediaQueryParser::readRestrictor)) {
47 m_state = &MediaQueryParser::done;
48 } else {
49 if (type == CommaToken)
50 --token;
51 m_state = &MediaQueryParser::skipTillComma;
52 }
53 }
54
55 void MediaQueryParser::readAnd(CSSTokenType type, TokenIterator& token)
56 {
57 if (type == IdentToken && token->value().lower() == "and") {
58 m_state = &MediaQueryParser::readFeatureStart;
59 } else if (type == CommaToken) {
60 m_mediaQueryData.addCurrentMediaQuery();
61 m_state = &MediaQueryParser::readRestrictor;
62 } else if (type == EOFToken) {
63 m_state = &MediaQueryParser::done;
64 } else {
65 m_state = &MediaQueryParser::skipTillComma;
66 }
67 }
68
69 void MediaQueryParser::readFeatureStart(CSSTokenType type, TokenIterator& token)
70 {
71 if (type == LeftParenToken)
72 m_state = &MediaQueryParser::readFeature;
73 else
74 m_state = &MediaQueryParser::skipTillComma;
75 }
76
77 void MediaQueryParser::readFeature(CSSTokenType type, TokenIterator& token)
78 {
79 if (type == IdentToken) {
80 m_mediaQueryData.setMediaFeature(token->value());
81 m_state = &MediaQueryParser::readFeatureColon;
82 } else {
83 m_state = &MediaQueryParser::skipTillComma;
84 }
85 }
86
87 void MediaQueryParser::readFeatureColon(CSSTokenType type, TokenIterator& token)
88 {
89 if (type == ColonToken) {
90 m_state = &MediaQueryParser::readFeatureValue;
91 } else if (type == RightParenToken || type == EOFToken) {
92 --token;
93 m_state = &MediaQueryParser::readFeatureEnd;
94 } else {
95 m_state = &MediaQueryParser::skipTillParen;
96 }
97 }
98
99 void MediaQueryParser::readFeatureValue(CSSTokenType type, TokenIterator& token)
100 {
101 if (type == DimensionToken && token->unitType() == CSSPrimitiveValue::CSS_UN KNOWN) {
102 m_state = &MediaQueryParser::skipTillComma;
103 } else {
104 m_mediaQueryData.addParserValue(type, token);
105 m_state = &MediaQueryParser::readFeatureEnd;
106 }
107 }
108
109 void MediaQueryParser::readFeatureEnd(CSSTokenType type, TokenIterator& token)
110 {
111 if (type == RightParenToken || type == EOFToken) {
112 if (m_mediaQueryData.addExpression())
113 m_state = &MediaQueryParser::readAnd;
114 else
115 m_state = &MediaQueryParser::skipTillComma;
116 } else if (type == DelimToken && token->delimiter() == '/') {
117 m_mediaQueryData.addParserValue(type, token);
118 m_state = &MediaQueryParser::readFeatureValue;
119 } else {
120 m_state = &MediaQueryParser::skipTillParen;
121 }
122 }
123
124 void MediaQueryParser::skipTillComma(CSSTokenType type, TokenIterator& token)
125 {
126 if (type == CommaToken || type == EOFToken) {
127 m_state = &MediaQueryParser::readRestrictor;
128 m_mediaQueryData.resetCurrentQuery();
129 m_mediaQueryData.addNotAllMediaQuery();
130 }
131 }
132
133 void MediaQueryParser::skipTillParen(CSSTokenType type, TokenIterator& token)
134 {
135 if (type == RightParenToken)
136 m_state = &MediaQueryParser::skipTillComma;
137 }
138
139 void MediaQueryParser::done(CSSTokenType type, TokenIterator& token) { }
140
141 // The state machine loop
142 PassRefPtr<MediaQuerySet> MediaQueryParser::parseImpl()
143 {
144 CSSTokenType type;
145
146 for (Vector<CSSToken>::iterator token = m_tokens.begin(); token != m_tokens. end(); ++token) {
147 type = token->type();
148 if (type == WhitespaceToken)
149 continue;
150
151 // Call the function that handles current state
152 ((this)->*(m_state))(type, token);
153 }
154
155 if (m_state != &MediaQueryParser::readAnd && m_state != &MediaQueryParser::r eadRestrictor && m_state != &MediaQueryParser::done)
156 m_mediaQueryData.addNotAllMediaQuery();
157 else if (m_mediaQueryData.currentMediaQueryChanged())
158 m_mediaQueryData.addCurrentMediaQuery();
159
160 return m_mediaQueryData.querySet();
161 }
162
163 MediaQueryData::MediaQueryData()
164 : m_querySet(MediaQuerySet::create())
165 , m_restrictor(MediaQuery::None)
166 , m_mediaType("all")
167 , m_expressions(adoptPtr(new ExpressionVector()))
168 , m_mediaTypeSet(false)
169 {
170 }
171
172 void MediaQueryData::resetCurrentQuery()
173 {
174 m_mediaType = "all";
175 m_mediaTypeSet = false;
176 m_mediaFeature = "";
177 m_restrictor = MediaQuery::None;
178 m_valueList.clear();
179 m_expressions = adoptPtr(new ExpressionVector());
180 }
181
182 void MediaQueryData::addCurrentMediaQuery()
183 {
184 m_querySet->addMediaQuery(adoptPtr(new MediaQuery(m_restrictor, m_mediaType, m_expressions.release())));
185 resetCurrentQuery();
186 }
187
188 bool MediaQueryData::addExpression()
189 {
190 OwnPtr<MediaQueryExp> expression = MediaQueryExp::create(m_mediaFeature, &(m _valueList));
191 bool retValue = (expression != nullptr);
192 m_expressions->append(expression.release());
193 m_valueList.clear();
194 return retValue;
195 }
196
197 void MediaQueryData::addParserValue(CSSTokenType type, CSSToken* token)
198 {
199 CSSParserValue value;
200 if (type == NumberToken || type == PercentageToken || type == DimensionToken ) {
201 value.setFromNumber(token->numericValue(), token->unitType());
202 value.isInt = (token->numericValueType() == IntegerValueType);
203 } else if (type == DelimToken) {
204 value.unit = CSSParserValue::Operator;
205 value.iValue = token->delimiter();
206 } else {
207 CSSParserFunction* function = new CSSParserFunction;
208 function->name.init(token->value());
209 value.setFromFunction(function);
210 CSSParserString tokenValue;
211 tokenValue.init(token->value());
212 value.id = cssValueKeywordID(tokenValue);
213 }
214 m_valueList.addValue(value);
215 }
216
217 void MediaQueryData::setMediaType(const String& mediaType)
218 {
219 m_mediaType = mediaType;
220 m_mediaTypeSet = true;
221 }
222
223 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698