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

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: Moar rebase Created 6 years, 9 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 "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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698