summaryrefslogtreecommitdiff
path: root/Source/WebCore/css/parser/MediaQueryParser.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/css/parser/MediaQueryParser.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/css/parser/MediaQueryParser.cpp')
-rw-r--r--Source/WebCore/css/parser/MediaQueryParser.cpp310
1 files changed, 310 insertions, 0 deletions
diff --git a/Source/WebCore/css/parser/MediaQueryParser.cpp b/Source/WebCore/css/parser/MediaQueryParser.cpp
new file mode 100644
index 000000000..a4c9afe98
--- /dev/null
+++ b/Source/WebCore/css/parser/MediaQueryParser.cpp
@@ -0,0 +1,310 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+#include "MediaQueryParser.h"
+
+#include "CSSParserIdioms.h"
+#include "CSSTokenizer.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+RefPtr<MediaQuerySet> MediaQueryParser::parseMediaQuerySet(const String& queryString)
+{
+ return parseMediaQuerySet(CSSTokenizer(queryString).tokenRange());
+}
+
+RefPtr<MediaQuerySet> MediaQueryParser::parseMediaQuerySet(CSSParserTokenRange range)
+{
+ return MediaQueryParser(MediaQuerySetParser).parseInternal(range);
+}
+
+RefPtr<MediaQuerySet> MediaQueryParser::parseMediaCondition(CSSParserTokenRange range)
+{
+ return MediaQueryParser(MediaConditionParser).parseInternal(range);
+}
+
+const MediaQueryParser::State MediaQueryParser::ReadRestrictor = &MediaQueryParser::readRestrictor;
+const MediaQueryParser::State MediaQueryParser::ReadMediaNot = &MediaQueryParser::readMediaNot;
+const MediaQueryParser::State MediaQueryParser::ReadMediaType = &MediaQueryParser::readMediaType;
+const MediaQueryParser::State MediaQueryParser::ReadAnd = &MediaQueryParser::readAnd;
+const MediaQueryParser::State MediaQueryParser::ReadFeatureStart = &MediaQueryParser::readFeatureStart;
+const MediaQueryParser::State MediaQueryParser::ReadFeature = &MediaQueryParser::readFeature;
+const MediaQueryParser::State MediaQueryParser::ReadFeatureColon = &MediaQueryParser::readFeatureColon;
+const MediaQueryParser::State MediaQueryParser::ReadFeatureValue = &MediaQueryParser::readFeatureValue;
+const MediaQueryParser::State MediaQueryParser::ReadFeatureEnd = &MediaQueryParser::readFeatureEnd;
+const MediaQueryParser::State MediaQueryParser::SkipUntilComma = &MediaQueryParser::skipUntilComma;
+const MediaQueryParser::State MediaQueryParser::SkipUntilBlockEnd = &MediaQueryParser::skipUntilBlockEnd;
+const MediaQueryParser::State MediaQueryParser::Done = &MediaQueryParser::done;
+
+MediaQueryParser::MediaQueryParser(ParserType parserType)
+ : m_parserType(parserType)
+ , m_querySet(MediaQuerySet::create())
+{
+ if (parserType == MediaQuerySetParser)
+ m_state = &MediaQueryParser::readRestrictor;
+ else // MediaConditionParser
+ m_state = &MediaQueryParser::readMediaNot;
+}
+
+MediaQueryParser::~MediaQueryParser() { }
+
+void MediaQueryParser::setStateAndRestrict(State state, MediaQuery::Restrictor restrictor)
+{
+ m_mediaQueryData.setRestrictor(restrictor);
+ m_state = state;
+}
+
+// State machine member functions start here
+void MediaQueryParser::readRestrictor(CSSParserTokenType type, const CSSParserToken& token)
+{
+ readMediaType(type, token);
+}
+
+void MediaQueryParser::readMediaNot(CSSParserTokenType type, const CSSParserToken& token)
+{
+ if (type == IdentToken && equalIgnoringASCIICase(token.value(), "not"))
+ setStateAndRestrict(ReadFeatureStart, MediaQuery::Not);
+ else
+ readFeatureStart(type, token);
+}
+
+static bool isRestrictorOrLogicalOperator(const CSSParserToken& token)
+{
+ // FIXME: it would be more efficient to use lower-case always for tokenValue.
+ return equalIgnoringASCIICase(token.value(), "not")
+ || equalIgnoringASCIICase(token.value(), "and")
+ || equalIgnoringASCIICase(token.value(), "or")
+ || equalIgnoringASCIICase(token.value(), "only");
+}
+
+void MediaQueryParser::readMediaType(CSSParserTokenType type, const CSSParserToken& token)
+{
+ if (type == LeftParenthesisToken) {
+ if (m_mediaQueryData.restrictor() != MediaQuery::None)
+ m_state = SkipUntilComma;
+ else
+ m_state = ReadFeature;
+ } else if (type == IdentToken) {
+ if (m_state == ReadRestrictor && equalIgnoringASCIICase(token.value(), "not"))
+ setStateAndRestrict(ReadMediaType, MediaQuery::Not);
+ else if (m_state == ReadRestrictor && equalIgnoringASCIICase(token.value(), "only"))
+ setStateAndRestrict(ReadMediaType, MediaQuery::Only);
+ else if (m_mediaQueryData.restrictor() != MediaQuery::None
+ && isRestrictorOrLogicalOperator(token)) {
+ m_state = SkipUntilComma;
+ } else {
+ m_mediaQueryData.setMediaType(token.value().toString());
+ m_state = ReadAnd;
+ }
+ } else if (type == EOFToken && (!m_querySet->queryVector().size() || m_state != ReadRestrictor))
+ m_state = Done;
+ else {
+ m_state = SkipUntilComma;
+ if (type == CommaToken)
+ skipUntilComma(type, token);
+ }
+}
+
+void MediaQueryParser::commitMediaQuery()
+{
+ // FIXME-NEWPARSER: Convoluted and awful, but we can't change the MediaQuerySet yet because of the
+ // old parser.
+ MediaQuery mediaQuery = MediaQuery(m_mediaQueryData.restrictor(), m_mediaQueryData.mediaType(), WTFMove(m_mediaQueryData.expressions()));
+ m_mediaQueryData.clear();
+ m_querySet->addMediaQuery(WTFMove(mediaQuery));
+}
+
+void MediaQueryParser::readAnd(CSSParserTokenType type, const CSSParserToken& token)
+{
+ if (type == IdentToken && equalIgnoringASCIICase(token.value(), "and")) {
+ m_state = ReadFeatureStart;
+ } else if (type == CommaToken && m_parserType != MediaConditionParser) {
+ commitMediaQuery();
+ m_state = ReadRestrictor;
+ } else if (type == EOFToken)
+ m_state = Done;
+ else
+ m_state = SkipUntilComma;
+}
+
+void MediaQueryParser::readFeatureStart(CSSParserTokenType type, const CSSParserToken& /*token*/)
+{
+ if (type == LeftParenthesisToken)
+ m_state = ReadFeature;
+ else
+ m_state = SkipUntilComma;
+}
+
+void MediaQueryParser::readFeature(CSSParserTokenType type, const CSSParserToken& token)
+{
+ if (type == IdentToken) {
+ m_mediaQueryData.setMediaFeature(token.value().toString());
+ m_state = ReadFeatureColon;
+ } else
+ m_state = SkipUntilComma;
+}
+
+void MediaQueryParser::readFeatureColon(CSSParserTokenType type, const CSSParserToken& token)
+{
+ if (type == ColonToken)
+ m_state = ReadFeatureValue;
+ else if (type == RightParenthesisToken || type == EOFToken)
+ readFeatureEnd(type, token);
+ else
+ m_state = SkipUntilBlockEnd;
+}
+
+void MediaQueryParser::readFeatureValue(CSSParserTokenType type, const CSSParserToken& token)
+{
+ if (type == DimensionToken && token.unitType() == CSSPrimitiveValue::UnitType::CSS_UNKNOWN)
+ m_state = SkipUntilComma;
+ else {
+ if (m_mediaQueryData.tryAddParserToken(type, token))
+ m_state = ReadFeatureEnd;
+ else
+ m_state = SkipUntilBlockEnd;
+ }
+}
+
+void MediaQueryParser::readFeatureEnd(CSSParserTokenType type, const CSSParserToken& token)
+{
+ if (type == RightParenthesisToken || type == EOFToken) {
+ if (type != EOFToken && m_mediaQueryData.addExpression())
+ m_state = ReadAnd;
+ else
+ m_state = SkipUntilComma;
+ } else if (type == DelimiterToken && token.delimiter() == '/') {
+ m_mediaQueryData.tryAddParserToken(type, token);
+ m_state = ReadFeatureValue;
+ } else
+ m_state = SkipUntilBlockEnd;
+}
+
+void MediaQueryParser::skipUntilComma(CSSParserTokenType type, const CSSParserToken& /*token*/)
+{
+ if ((type == CommaToken && !m_blockWatcher.blockLevel()) || type == EOFToken) {
+ m_state = ReadRestrictor;
+ m_mediaQueryData.clear();
+ MediaQuery query = MediaQuery(MediaQuery::Not, "all", Vector<MediaQueryExpression>());
+ m_querySet->addMediaQuery(WTFMove(query));
+ }
+}
+
+void MediaQueryParser::skipUntilBlockEnd(CSSParserTokenType /*type */, const CSSParserToken& token)
+{
+ if (token.getBlockType() == CSSParserToken::BlockEnd && !m_blockWatcher.blockLevel())
+ m_state = SkipUntilComma;
+}
+
+void MediaQueryParser::done(CSSParserTokenType /*type*/, const CSSParserToken& /*token*/) { }
+
+void MediaQueryParser::handleBlocks(const CSSParserToken& token)
+{
+ if (token.getBlockType() == CSSParserToken::BlockStart
+ && (token.type() != LeftParenthesisToken || m_blockWatcher.blockLevel()))
+ m_state = SkipUntilBlockEnd;
+}
+
+void MediaQueryParser::processToken(const CSSParserToken& token)
+{
+ CSSParserTokenType type = token.type();
+
+ handleBlocks(token);
+ m_blockWatcher.handleToken(token);
+
+ // Call the function that handles current state
+ if (type != WhitespaceToken)
+ ((this)->*(m_state))(type, token);
+}
+
+// The state machine loop
+RefPtr<MediaQuerySet> MediaQueryParser::parseInternal(CSSParserTokenRange range)
+{
+ while (!range.atEnd())
+ processToken(range.consume());
+
+ // FIXME: Can we get rid of this special case?
+ if (m_parserType == MediaQuerySetParser)
+ processToken(CSSParserToken(EOFToken));
+
+ if (m_state != ReadAnd && m_state != ReadRestrictor && m_state != Done && m_state != ReadMediaNot) {
+ MediaQuery query = MediaQuery(MediaQuery::Not, "all", Vector<MediaQueryExpression>());
+ m_querySet->addMediaQuery(WTFMove(query));
+ } else if (m_mediaQueryData.currentMediaQueryChanged())
+ commitMediaQuery();
+
+ return m_querySet;
+}
+
+MediaQueryData::MediaQueryData()
+ : m_restrictor(MediaQuery::None)
+ , m_mediaType("all")
+ , m_mediaTypeSet(false)
+{
+}
+
+void MediaQueryData::clear()
+{
+ m_restrictor = MediaQuery::None;
+ m_mediaType = "all";
+ m_mediaTypeSet = false;
+ m_mediaFeature = String();
+ m_valueList.clear();
+ m_expressions.clear();
+}
+
+bool MediaQueryData::addExpression()
+{
+ MediaQueryExpression expression = MediaQueryExpression(m_mediaFeature, m_valueList);
+ bool isValid = expression.isValid();
+ m_expressions.append(WTFMove(expression));
+ m_valueList.clear();
+ return isValid;
+}
+
+bool MediaQueryData::tryAddParserToken(CSSParserTokenType type, const CSSParserToken& token)
+{
+ if (type == NumberToken || type == PercentageToken || type == DimensionToken
+ || type == DelimiterToken || type == IdentToken) {
+ m_valueList.append(token);
+ return true;
+ }
+
+ return false;
+}
+
+void MediaQueryData::setMediaType(const String& mediaType)
+{
+ m_mediaType = mediaType;
+ m_mediaTypeSet = true;
+}
+
+} // namespace WebCsore