diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/css/parser/MediaQueryParser.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/css/parser/MediaQueryParser.cpp')
-rw-r--r-- | Source/WebCore/css/parser/MediaQueryParser.cpp | 310 |
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 |