OLD | NEW |
| (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 "MediaTypeNames.h" | |
9 #include "core/css/parser/CSSPropertyParser.h" | |
10 #include "core/css/parser/MediaQueryTokenizer.h" | |
11 | |
12 namespace WebCore { | |
13 | |
14 PassRefPtrWillBeRawPtr<MediaQuerySet> MediaQueryParser::parse(const String& quer
yString) | |
15 { | |
16 return MediaQueryParser(queryString).parseImpl(); | |
17 } | |
18 | |
19 const MediaQueryParser::State MediaQueryParser::ReadRestrictor = &MediaQueryPars
er::readRestrictor; | |
20 const MediaQueryParser::State MediaQueryParser::ReadMediaType = &MediaQueryParse
r::readMediaType; | |
21 const MediaQueryParser::State MediaQueryParser::ReadAnd = &MediaQueryParser::rea
dAnd; | |
22 const MediaQueryParser::State MediaQueryParser::ReadFeatureStart = &MediaQueryPa
rser::readFeatureStart; | |
23 const MediaQueryParser::State MediaQueryParser::ReadFeature = &MediaQueryParser:
:readFeature; | |
24 const MediaQueryParser::State MediaQueryParser::ReadFeatureColon = &MediaQueryPa
rser::readFeatureColon; | |
25 const MediaQueryParser::State MediaQueryParser::ReadFeatureValue = &MediaQueryPa
rser::readFeatureValue; | |
26 const MediaQueryParser::State MediaQueryParser::ReadFeatureEnd = &MediaQueryPars
er::readFeatureEnd; | |
27 const MediaQueryParser::State MediaQueryParser::SkipUntilComma = &MediaQueryPars
er::skipUntilComma; | |
28 const MediaQueryParser::State MediaQueryParser::SkipUntilParenthesis = &MediaQue
ryParser::skipUntilParenthesis; | |
29 const MediaQueryParser::State MediaQueryParser::Done = &MediaQueryParser::done; | |
30 | |
31 // FIXME: Replace the MediaQueryTokenizer with a generic CSSTokenizer, once ther
e is one, | |
32 // or better yet, replace the MediaQueryParser with a generic thread-safe CSS pa
rser. | |
33 MediaQueryParser::MediaQueryParser(const String& queryString) | |
34 : m_state(&MediaQueryParser::readRestrictor) | |
35 , m_querySet(MediaQuerySet::create()) | |
36 { | |
37 MediaQueryTokenizer::tokenize(queryString, m_tokens); | |
38 } | |
39 | |
40 void MediaQueryParser::setStateAndRestrict(State state, MediaQuery::Restrictor r
estrictor) | |
41 { | |
42 m_mediaQueryData.setRestrictor(restrictor); | |
43 m_state = state; | |
44 } | |
45 | |
46 // State machine member functions start here | |
47 void MediaQueryParser::readRestrictor(MediaQueryTokenType type, TokenIterator& t
oken) | |
48 { | |
49 readMediaType(type, token); | |
50 } | |
51 | |
52 void MediaQueryParser::readMediaType(MediaQueryTokenType type, TokenIterator& to
ken) | |
53 { | |
54 if (type == LeftParenthesisToken) { | |
55 m_state = ReadFeature; | |
56 } else if (type == IdentToken) { | |
57 if (m_state == ReadRestrictor && equalIgnoringCase(token->value(), "not"
)) { | |
58 setStateAndRestrict(ReadMediaType, MediaQuery::Not); | |
59 } else if (m_state == ReadRestrictor && equalIgnoringCase(token->value()
, "only")) { | |
60 setStateAndRestrict(ReadMediaType, MediaQuery::Only); | |
61 } else { | |
62 m_mediaQueryData.setMediaType(token->value()); | |
63 m_state = ReadAnd; | |
64 } | |
65 } else if (type == EOFToken && (!m_querySet->queryVector().size() || m_state
!= ReadRestrictor)) { | |
66 m_state = Done; | |
67 } else { | |
68 if (type == CommaToken) | |
69 --token; | |
70 m_state = SkipUntilComma; | |
71 } | |
72 } | |
73 | |
74 void MediaQueryParser::readAnd(MediaQueryTokenType type, TokenIterator& token) | |
75 { | |
76 if (type == IdentToken && equalIgnoringCase(token->value(), "and")) { | |
77 m_state = ReadFeatureStart; | |
78 } else if (type == CommaToken) { | |
79 m_querySet->addMediaQuery(m_mediaQueryData.takeMediaQuery()); | |
80 m_state = ReadRestrictor; | |
81 } else if (type == EOFToken) { | |
82 m_state = Done; | |
83 } else { | |
84 m_state = SkipUntilComma; | |
85 } | |
86 } | |
87 | |
88 void MediaQueryParser::readFeatureStart(MediaQueryTokenType type, TokenIterator&
token) | |
89 { | |
90 if (type == LeftParenthesisToken) | |
91 m_state = ReadFeature; | |
92 else | |
93 m_state = SkipUntilComma; | |
94 } | |
95 | |
96 void MediaQueryParser::readFeature(MediaQueryTokenType type, TokenIterator& toke
n) | |
97 { | |
98 if (type == IdentToken) { | |
99 m_mediaQueryData.setMediaFeature(token->value()); | |
100 m_state = ReadFeatureColon; | |
101 } else { | |
102 m_state = SkipUntilComma; | |
103 } | |
104 } | |
105 | |
106 void MediaQueryParser::readFeatureColon(MediaQueryTokenType type, TokenIterator&
token) | |
107 { | |
108 if (type == ColonToken) { | |
109 m_state = ReadFeatureValue; | |
110 } else if (type == RightParenthesisToken || type == EOFToken) { | |
111 --token; | |
112 m_state = ReadFeatureEnd; | |
113 } else { | |
114 m_state = SkipUntilParenthesis; | |
115 } | |
116 } | |
117 | |
118 void MediaQueryParser::readFeatureValue(MediaQueryTokenType type, TokenIterator&
token) | |
119 { | |
120 if (type == DimensionToken && token->unitType() == CSSPrimitiveValue::CSS_UN
KNOWN) { | |
121 m_state = SkipUntilComma; | |
122 } else { | |
123 m_mediaQueryData.addParserValue(type, *token); | |
124 m_state = ReadFeatureEnd; | |
125 } | |
126 } | |
127 | |
128 void MediaQueryParser::readFeatureEnd(MediaQueryTokenType type, TokenIterator& t
oken) | |
129 { | |
130 if (type == RightParenthesisToken || type == EOFToken) { | |
131 if (m_mediaQueryData.addExpression()) | |
132 m_state = ReadAnd; | |
133 else | |
134 m_state = SkipUntilComma; | |
135 } else if (type == DelimiterToken && token->delimiter() == '/') { | |
136 m_mediaQueryData.addParserValue(type, *token); | |
137 m_state = ReadFeatureValue; | |
138 } else { | |
139 m_state = SkipUntilParenthesis; | |
140 } | |
141 } | |
142 | |
143 void MediaQueryParser::skipUntilComma(MediaQueryTokenType type, TokenIterator& t
oken) | |
144 { | |
145 if (type == CommaToken || type == EOFToken) { | |
146 m_state = ReadRestrictor; | |
147 m_mediaQueryData.clear(); | |
148 m_querySet->addMediaQuery(MediaQuery::createNotAll()); | |
149 } | |
150 } | |
151 | |
152 void MediaQueryParser::skipUntilParenthesis(MediaQueryTokenType type, TokenItera
tor& token) | |
153 { | |
154 if (type == RightParenthesisToken) | |
155 m_state = SkipUntilComma; | |
156 } | |
157 | |
158 void MediaQueryParser::done(MediaQueryTokenType type, TokenIterator& token) { } | |
159 | |
160 void MediaQueryParser::processToken(TokenIterator& token) | |
161 { | |
162 MediaQueryTokenType type = token->type(); | |
163 | |
164 // Call the function that handles current state | |
165 if (type != WhitespaceToken) | |
166 ((this)->*(m_state))(type, token); | |
167 } | |
168 | |
169 // The state machine loop | |
170 PassRefPtrWillBeRawPtr<MediaQuerySet> MediaQueryParser::parseImpl() | |
171 { | |
172 for (Vector<MediaQueryToken>::iterator token = m_tokens.begin(); token != m_
tokens.end(); ++token) | |
173 processToken(token); | |
174 | |
175 if (m_state != ReadAnd && m_state != ReadRestrictor && m_state != Done) | |
176 m_querySet->addMediaQuery(MediaQuery::createNotAll()); | |
177 else if (m_mediaQueryData.currentMediaQueryChanged()) | |
178 m_querySet->addMediaQuery(m_mediaQueryData.takeMediaQuery()); | |
179 | |
180 return m_querySet; | |
181 } | |
182 | |
183 MediaQueryData::MediaQueryData() | |
184 : m_restrictor(MediaQuery::None) | |
185 , m_mediaType(MediaTypeNames::all) | |
186 , m_expressions(adoptPtr(new ExpressionHeapVector)) | |
187 , m_mediaTypeSet(false) | |
188 { | |
189 } | |
190 | |
191 void MediaQueryData::clear() | |
192 { | |
193 m_restrictor = MediaQuery::None; | |
194 m_mediaType = MediaTypeNames::all; | |
195 m_mediaTypeSet = false; | |
196 m_mediaFeature = String(); | |
197 m_valueList.clear(); | |
198 m_expressions = adoptPtr(new ExpressionHeapVector); | |
199 } | |
200 | |
201 PassOwnPtr<MediaQuery> MediaQueryData::takeMediaQuery() | |
202 { | |
203 OwnPtr<MediaQuery> mediaQuery = adoptPtr(new MediaQuery(m_restrictor, m_medi
aType, m_expressions.release())); | |
204 clear(); | |
205 return mediaQuery.release(); | |
206 } | |
207 | |
208 bool MediaQueryData::addExpression() | |
209 { | |
210 OwnPtr<MediaQueryExp> expression = MediaQueryExp::create(m_mediaFeature, &m_
valueList); | |
211 bool isValid = !!expression; | |
212 m_expressions->append(expression.release()); | |
213 m_valueList.clear(); | |
214 return isValid; | |
215 } | |
216 | |
217 void MediaQueryData::addParserValue(MediaQueryTokenType type, MediaQueryToken& t
oken) | |
218 { | |
219 CSSParserValue value; | |
220 if (type == NumberToken || type == PercentageToken || type == DimensionToken
) { | |
221 value.setFromNumber(token.numericValue(), token.unitType()); | |
222 value.isInt = (token.numericValueType() == IntegerValueType); | |
223 } else if (type == DelimiterToken) { | |
224 value.unit = CSSParserValue::Operator; | |
225 value.iValue = token.delimiter(); | |
226 } else { | |
227 CSSParserFunction* function = new CSSParserFunction; | |
228 function->name.init(token.value()); | |
229 value.setFromFunction(function); | |
230 CSSParserString tokenValue; | |
231 tokenValue.init(token.value()); | |
232 value.id = cssValueKeywordID(tokenValue); | |
233 } | |
234 m_valueList.addValue(value); | |
235 } | |
236 | |
237 void MediaQueryData::setMediaType(const String& mediaType) | |
238 { | |
239 m_mediaType = mediaType; | |
240 m_mediaTypeSet = true; | |
241 } | |
242 | |
243 } // namespace WebCore | |
OLD | NEW |