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