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

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: Another comment fixed 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(String queryString )
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(String queryString)
eseidel 2014/03/11 20:14:19 I think String is normally passed const String&?
23 : m_state(&MediaQueryParser::readRestrictor)
24 {
25 MediaQueryTokenizer::tokenize(queryString, m_tokens);
26 }
27
28 // State machine member functions start here
29 void MediaQueryParser::readRestrictor(MediaQueryTokenType type, TokenIterator& t oken)
30 {
31 readMediaType(type, token);
32 }
33
34 void MediaQueryParser::readMediaType(MediaQueryTokenType type, TokenIterator& to ken)
35 {
36 if (type == LeftParenthesisToken) {
37 m_state = &MediaQueryParser::readFeature;
eseidel 2014/03/11 20:14:19 Intersting that you're using function pointers as
Yoav Weiss 2014/03/12 20:39:00 I like that :)
38 } else if (type == IdentToken) {
39 if (m_state == &MediaQueryParser::readRestrictor && token->value().lower () == "not") {
eseidel 2014/03/11 20:14:19 We have case-insensitive comparison functions. eq
40 m_mediaQueryData.setRestrictor(MediaQuery::Not);
eseidel 2014/03/11 20:14:19 If these are often tied, you might add a helper me
41 m_state = &MediaQueryParser::readMediaType;
42 } else if (m_state == &MediaQueryParser::readRestrictor && token->value( ).lower() == "only") {
43 m_mediaQueryData.setRestrictor(MediaQuery::Only);
44 m_state = &MediaQueryParser::readMediaType;
45 } else {
46 m_mediaQueryData.setMediaType(token->value());
47 m_state = &MediaQueryParser::readAnd;
48 }
49 } else if (type == EOFToken && (!m_mediaQueryData.querySetSize() || m_state != &MediaQueryParser::readRestrictor)) {
50 m_state = &MediaQueryParser::done;
51 } else {
52 if (type == CommaToken)
53 --token;
54 m_state = &MediaQueryParser::skipUntilComma;
55 }
56 }
57
58 void MediaQueryParser::readAnd(MediaQueryTokenType type, TokenIterator& token)
59 {
60 if (type == IdentToken && token->value().lower() == "and") {
61 m_state = &MediaQueryParser::readFeatureStart;
62 } else if (type == CommaToken) {
63 m_mediaQueryData.addCurrentMediaQuery();
64 m_state = &MediaQueryParser::readRestrictor;
65 } else if (type == EOFToken) {
66 m_state = &MediaQueryParser::done;
67 } else {
68 m_state = &MediaQueryParser::skipUntilComma;
69 }
70 }
71
72 void MediaQueryParser::readFeatureStart(MediaQueryTokenType type, TokenIterator& token)
73 {
74 if (type == LeftParenthesisToken)
75 m_state = &MediaQueryParser::readFeature;
76 else
77 m_state = &MediaQueryParser::skipUntilComma;
78 }
79
80 void MediaQueryParser::readFeature(MediaQueryTokenType type, TokenIterator& toke n)
81 {
82 if (type == IdentToken) {
83 m_mediaQueryData.setMediaFeature(token->value());
84 m_state = &MediaQueryParser::readFeatureColon;
85 } else {
86 m_state = &MediaQueryParser::skipUntilComma;
87 }
88 }
89
90 void MediaQueryParser::readFeatureColon(MediaQueryTokenType type, TokenIterator& token)
91 {
92 if (type == ColonToken) {
93 m_state = &MediaQueryParser::readFeatureValue;
94 } else if (type == RightParenthesisToken || type == EOFToken) {
95 --token;
96 m_state = &MediaQueryParser::readFeatureEnd;
97 } else {
98 m_state = &MediaQueryParser::skipUntilParenthesis;
99 }
100 }
101
102 void MediaQueryParser::readFeatureValue(MediaQueryTokenType type, TokenIterator& token)
103 {
104 if (type == DimensionToken && token->unitType() == CSSPrimitiveValue::CSS_UN KNOWN) {
105 m_state = &MediaQueryParser::skipUntilComma;
106 } else {
107 m_mediaQueryData.addParserValue(type, token);
108 m_state = &MediaQueryParser::readFeatureEnd;
109 }
110 }
111
112 void MediaQueryParser::readFeatureEnd(MediaQueryTokenType type, TokenIterator& t oken)
113 {
114 if (type == RightParenthesisToken || type == EOFToken) {
115 if (m_mediaQueryData.addExpression())
116 m_state = &MediaQueryParser::readAnd;
117 else
118 m_state = &MediaQueryParser::skipUntilComma;
119 } else if (type == DelimiterToken && token->delimiter() == '/') {
120 m_mediaQueryData.addParserValue(type, token);
121 m_state = &MediaQueryParser::readFeatureValue;
122 } else {
123 m_state = &MediaQueryParser::skipUntilParenthesis;
124 }
125 }
126
127 void MediaQueryParser::skipUntilComma(MediaQueryTokenType type, TokenIterator& t oken)
128 {
129 if (type == CommaToken || type == EOFToken) {
130 m_state = &MediaQueryParser::readRestrictor;
131 m_mediaQueryData.resetCurrentQuery();
132 m_mediaQueryData.addNotAllMediaQuery();
133 }
134 }
135
136 void MediaQueryParser::skipUntilParenthesis(MediaQueryTokenType type, TokenItera tor& token)
137 {
138 if (type == RightParenthesisToken)
139 m_state = &MediaQueryParser::skipUntilComma;
140 }
141
142 void MediaQueryParser::done(MediaQueryTokenType type, TokenIterator& token) { }
143
144 // The state machine loop
145 PassRefPtrWillBeRawPtr<MediaQuerySet> MediaQueryParser::parseImpl()
146 {
147 MediaQueryTokenType type;
148
149 for (Vector<MediaQueryToken>::iterator token = m_tokens.begin(); token != m_ tokens.end(); ++token) {
150 type = token->type();
151 if (type == WhitespaceToken)
152 continue;
153
154 // Call the function that handles current state
155 ((this)->*(m_state))(type, token);
eseidel 2014/03/11 20:14:19 I might have moved this loop body into a helper fu
156 }
157
158 if (m_state != &MediaQueryParser::readAnd && m_state != &MediaQueryParser::r eadRestrictor && m_state != &MediaQueryParser::done)
159 m_mediaQueryData.addNotAllMediaQuery();
160 else if (m_mediaQueryData.currentMediaQueryChanged())
161 m_mediaQueryData.addCurrentMediaQuery();
162
163 return m_mediaQueryData.querySet();
164 }
165
166 MediaQueryData::MediaQueryData()
167 : m_querySet(MediaQuerySet::create())
168 , m_restrictor(MediaQuery::None)
169 , m_mediaType(MediaTypeNames::all)
170 , m_expressions(adoptPtr(new ExpressionHeapVector()))
eseidel 2014/03/11 20:14:19 ExpressionHeapVector::create() is preferred if pos
Yoav Weiss 2014/03/12 20:39:00 ExpressionHeapVector is a typedef for a Vector. Sh
171 , m_mediaTypeSet(false)
172 {
173 }
174
175 void MediaQueryData::resetCurrentQuery()
eseidel 2014/03/11 20:14:19 Does this store more than the "current query"? Sh
Yoav Weiss 2014/03/12 20:39:00 MediaQueryData also contains m_querySet that we do
176 {
177 m_mediaType = MediaTypeNames::all;
178 m_mediaTypeSet = false;
179 m_mediaFeature = "";
180 m_restrictor = MediaQuery::None;
181 m_valueList.clear();
182 m_expressions = adoptPtr(new ExpressionHeapVector());
183 }
184
185 void MediaQueryData::addCurrentMediaQuery()
186 {
187 m_querySet->addMediaQuery(adoptPtr(new MediaQuery(m_restrictor, m_mediaType, m_expressions.release())));
eseidel 2014/03/11 20:14:19 ::create() is better when possible, for hiding the
188 resetCurrentQuery();
eseidel 2014/03/11 20:14:19 Should this instead be: m_querySet->addMediaQuery
189 }
190
191 bool MediaQueryData::addExpression()
192 {
193 OwnPtr<MediaQueryExp> expression = MediaQueryExp::create(m_mediaFeature, &(m _valueList));
eseidel 2014/03/11 20:14:19 I don't think you need hte inner ()
194 bool retValue = (expression.get());
eseidel 2014/03/11 20:14:19 Or here. !! works too. bool hadExpression = !!exp
Yoav Weiss 2014/03/12 20:39:00 MediaQueryExp::create returns nullptr when the exp
195 m_expressions->append(expression.release());
196 m_valueList.clear();
197 return retValue;
198 }
199
200 void MediaQueryData::addParserValue(MediaQueryTokenType type, MediaQueryToken* t oken)
eseidel 2014/03/11 20:14:19 If Token can't ever be null in these functions it
201 {
202 CSSParserValue value;
203 if (type == NumberToken || type == PercentageToken || type == DimensionToken ) {
204 value.setFromNumber(token->numericValue(), token->unitType());
205 value.isInt = (token->numericValueType() == IntegerValueType);
206 } else if (type == DelimiterToken) {
207 value.unit = CSSParserValue::Operator;
208 value.iValue = token->delimiter();
209 } else {
210 CSSParserFunction* function = new CSSParserFunction;
eseidel 2014/03/11 20:14:19 Please use OwnPtr.
Yoav Weiss 2014/03/12 20:39:00 The owner of the CSSParserFunction needs to be the
211 function->name.init(token->value());
212 value.setFromFunction(function);
213 CSSParserString tokenValue;
214 tokenValue.init(token->value());
215 value.id = cssValueKeywordID(tokenValue);
216 }
217 m_valueList.addValue(value);
218 }
219
220 void MediaQueryData::setMediaType(const String& mediaType)
221 {
222 m_mediaType = mediaType;
223 m_mediaTypeSet = true;
224 }
225
226 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698