Index: Source/core/css/parser/MediaQueryParser.cpp |
diff --git a/Source/core/css/parser/MediaQueryParser.cpp b/Source/core/css/parser/MediaQueryParser.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3bd8150e520d42995595d08c3120390a77f3d9dd |
--- /dev/null |
+++ b/Source/core/css/parser/MediaQueryParser.cpp |
@@ -0,0 +1,224 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "config.h" |
+#include "core/css/parser/MediaQueryParser.h" |
+ |
+#include "MediaTypeNames.h" |
+#include "core/css/parser/CSSPropertyParser.h" |
+#include "core/css/parser/MediaQueryTokenizer.h" |
+ |
+namespace WebCore { |
+ |
+PassRefPtrWillBeRawPtr<MediaQuerySet> MediaQueryParser::parse(String queryString) |
+{ |
+ MediaQueryParser parser(queryString); |
+ return parser.parseImpl(); |
+} |
+ |
+MediaQueryParser::MediaQueryParser(String queryString) |
+ : m_state(&MediaQueryParser::readRestrictor) |
+{ |
+ MediaQueryTokenizer::tokenize(queryString, m_tokens); |
+} |
+ |
+// State machine member functions start here |
+void MediaQueryParser::readRestrictor(CSSTokenType type, TokenIterator& token) |
+{ |
+ readMediaType(type, token); |
+} |
+ |
+void MediaQueryParser::readMediaType(CSSTokenType type, TokenIterator& token) |
+{ |
+ if (type == LeftParenToken) { |
+ m_state = &MediaQueryParser::readFeature; |
+ } else if (type == IdentToken) { |
+ if (m_state == &MediaQueryParser::readRestrictor && token->value().lower() == "not") { |
+ m_mediaQueryData.setRestrictor(MediaQuery::Not); |
+ m_state = &MediaQueryParser::readMediaType; |
+ } else if (m_state == &MediaQueryParser::readRestrictor && token->value().lower() == "only") { |
+ m_mediaQueryData.setRestrictor(MediaQuery::Only); |
+ m_state = &MediaQueryParser::readMediaType; |
+ } else { |
+ m_mediaQueryData.setMediaType(token->value()); |
+ m_state = &MediaQueryParser::readAnd; |
+ } |
+ } else if (type == EOFToken && (!m_mediaQueryData.querySetSize() || m_state != &MediaQueryParser::readRestrictor)) { |
+ m_state = &MediaQueryParser::done; |
+ } else { |
+ if (type == CommaToken) |
+ --token; |
+ m_state = &MediaQueryParser::skipTillComma; |
+ } |
+} |
+ |
+void MediaQueryParser::readAnd(CSSTokenType type, TokenIterator& token) |
+{ |
+ if (type == IdentToken && token->value().lower() == "and") { |
+ m_state = &MediaQueryParser::readFeatureStart; |
+ } else if (type == CommaToken) { |
+ m_mediaQueryData.addCurrentMediaQuery(); |
+ m_state = &MediaQueryParser::readRestrictor; |
+ } else if (type == EOFToken) { |
+ m_state = &MediaQueryParser::done; |
+ } else { |
+ m_state = &MediaQueryParser::skipTillComma; |
+ } |
+} |
+ |
+void MediaQueryParser::readFeatureStart(CSSTokenType type, TokenIterator& token) |
+{ |
+ if (type == LeftParenToken) |
+ m_state = &MediaQueryParser::readFeature; |
+ else |
+ m_state = &MediaQueryParser::skipTillComma; |
+} |
+ |
+void MediaQueryParser::readFeature(CSSTokenType type, TokenIterator& token) |
+{ |
+ if (type == IdentToken) { |
+ m_mediaQueryData.setMediaFeature(token->value()); |
+ m_state = &MediaQueryParser::readFeatureColon; |
+ } else { |
+ m_state = &MediaQueryParser::skipTillComma; |
+ } |
+} |
+ |
+void MediaQueryParser::readFeatureColon(CSSTokenType type, TokenIterator& token) |
+{ |
+ if (type == ColonToken) { |
+ m_state = &MediaQueryParser::readFeatureValue; |
+ } else if (type == RightParenToken || type == EOFToken) { |
+ --token; |
+ m_state = &MediaQueryParser::readFeatureEnd; |
+ } else { |
+ m_state = &MediaQueryParser::skipTillParen; |
+ } |
+} |
+ |
+void MediaQueryParser::readFeatureValue(CSSTokenType type, TokenIterator& token) |
+{ |
+ if (type == DimensionToken && token->unitType() == CSSPrimitiveValue::CSS_UNKNOWN) { |
+ m_state = &MediaQueryParser::skipTillComma; |
+ } else { |
+ m_mediaQueryData.addParserValue(type, token); |
+ m_state = &MediaQueryParser::readFeatureEnd; |
+ } |
+} |
+ |
+void MediaQueryParser::readFeatureEnd(CSSTokenType type, TokenIterator& token) |
+{ |
+ if (type == RightParenToken || type == EOFToken) { |
+ if (m_mediaQueryData.addExpression()) |
+ m_state = &MediaQueryParser::readAnd; |
+ else |
+ m_state = &MediaQueryParser::skipTillComma; |
+ } else if (type == DelimToken && token->delimiter() == '/') { |
+ m_mediaQueryData.addParserValue(type, token); |
+ m_state = &MediaQueryParser::readFeatureValue; |
+ } else { |
+ m_state = &MediaQueryParser::skipTillParen; |
+ } |
+} |
+ |
+void MediaQueryParser::skipTillComma(CSSTokenType type, TokenIterator& token) |
+{ |
+ if (type == CommaToken || type == EOFToken) { |
+ m_state = &MediaQueryParser::readRestrictor; |
+ m_mediaQueryData.resetCurrentQuery(); |
+ m_mediaQueryData.addNotAllMediaQuery(); |
+ } |
+} |
+ |
+void MediaQueryParser::skipTillParen(CSSTokenType type, TokenIterator& token) |
+{ |
+ if (type == RightParenToken) |
+ m_state = &MediaQueryParser::skipTillComma; |
+} |
+ |
+void MediaQueryParser::done(CSSTokenType type, TokenIterator& token) { } |
+ |
+// The state machine loop |
+PassRefPtrWillBeRawPtr<MediaQuerySet> MediaQueryParser::parseImpl() |
+{ |
+ CSSTokenType type; |
+ |
+ for (Vector<CSSToken>::iterator token = m_tokens.begin(); token != m_tokens.end(); ++token) { |
+ type = token->type(); |
+ if (type == WhitespaceToken) |
+ continue; |
+ |
+ // Call the function that handles current state |
+ ((this)->*(m_state))(type, token); |
+ } |
+ |
+ if (m_state != &MediaQueryParser::readAnd && m_state != &MediaQueryParser::readRestrictor && m_state != &MediaQueryParser::done) |
+ m_mediaQueryData.addNotAllMediaQuery(); |
+ else if (m_mediaQueryData.currentMediaQueryChanged()) |
+ m_mediaQueryData.addCurrentMediaQuery(); |
+ |
+ return m_mediaQueryData.querySet(); |
+} |
+ |
+MediaQueryData::MediaQueryData() |
+ : m_querySet(MediaQuerySet::create()) |
+ , m_restrictor(MediaQuery::None) |
+ , m_mediaType(MediaTypeNames::all) |
+ , m_expressions(adoptPtr(new ExpressionHeapVector())) |
+ , m_mediaTypeSet(false) |
+{ |
+} |
+ |
+void MediaQueryData::resetCurrentQuery() |
+{ |
+ m_mediaType = MediaTypeNames::all; |
+ m_mediaTypeSet = false; |
+ m_mediaFeature = ""; |
+ m_restrictor = MediaQuery::None; |
+ m_valueList.clear(); |
+ m_expressions = adoptPtr(new ExpressionHeapVector()); |
+} |
+ |
+void MediaQueryData::addCurrentMediaQuery() |
+{ |
+ m_querySet->addMediaQuery(adoptPtr(new MediaQuery(m_restrictor, m_mediaType, m_expressions.release()))); |
+ resetCurrentQuery(); |
+} |
+ |
+bool MediaQueryData::addExpression() |
+{ |
+ OwnPtr<MediaQueryExp> expression = MediaQueryExp::create(m_mediaFeature, &(m_valueList)); |
+ bool retValue = (expression.get()); |
+ m_expressions->append(expression.release()); |
+ m_valueList.clear(); |
+ return retValue; |
+} |
+ |
+void MediaQueryData::addParserValue(CSSTokenType type, CSSToken* token) |
+{ |
+ CSSParserValue value; |
+ if (type == NumberToken || type == PercentageToken || type == DimensionToken) { |
+ value.setFromNumber(token->numericValue(), token->unitType()); |
+ value.isInt = (token->numericValueType() == IntegerValueType); |
+ } else if (type == DelimToken) { |
+ value.unit = CSSParserValue::Operator; |
+ value.iValue = token->delimiter(); |
+ } else { |
+ CSSParserFunction* function = new CSSParserFunction; |
+ function->name.init(token->value()); |
+ value.setFromFunction(function); |
+ CSSParserString tokenValue; |
+ tokenValue.init(token->value()); |
+ value.id = cssValueKeywordID(tokenValue); |
+ } |
+ m_valueList.addValue(value); |
+} |
+ |
+void MediaQueryData::setMediaType(const String& mediaType) |
+{ |
+ m_mediaType = mediaType; |
+ m_mediaTypeSet = true; |
+} |
+ |
+} // namespace WebCore |