blob: 43f1950615678c6c35625785fec3891cf0027b0a [file] [log] [blame]
// Copyright 2015 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 "third_party/blink/renderer/core/css/parser/css_supports_parser.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_impl.h"
namespace blink {
CSSSupportsParser::SupportsResult CSSSupportsParser::SupportsCondition(
CSSParserTokenRange range,
CSSParserImpl& parser,
SupportsParsingMode parsing_mode) {
range.ConsumeWhitespace();
CSSSupportsParser supports_parser(parser);
SupportsResult result = supports_parser.ConsumeCondition(range);
if (parsing_mode != kForWindowCSS || result != kInvalid)
return result;
// window.CSS.supports requires to parse as-if it was wrapped in parenthesis.
// The only wrapped production that wouldn't have parsed above is the
// declaration condition production.
return supports_parser.ConsumeDeclarationCondition(range);
}
enum ClauseType { kUnresolved, kConjunction, kDisjunction };
CSSSupportsParser::SupportsResult CSSSupportsParser::ConsumeCondition(
CSSParserTokenRange range) {
if (range.Peek().GetType() == kIdentToken)
return ConsumeNegation(range);
bool result;
ClauseType clause_type = kUnresolved;
while (true) {
SupportsResult next_result = ConsumeConditionInParenthesis(range);
if (next_result == kInvalid)
return kInvalid;
bool next_supported = next_result;
if (clause_type == kUnresolved)
result = next_supported;
else if (clause_type == kConjunction)
result &= next_supported;
else
result |= next_supported;
if (range.AtEnd())
break;
if (range.ConsumeIncludingWhitespace().GetType() != kWhitespaceToken)
return kInvalid;
if (range.AtEnd())
break;
const CSSParserToken& token = range.Consume();
if (token.GetType() != kIdentToken)
return kInvalid;
if (clause_type == kUnresolved)
clause_type = token.Value().length() == 3 ? kConjunction : kDisjunction;
if ((clause_type == kConjunction &&
!EqualIgnoringASCIICase(token.Value(), "and")) ||
(clause_type == kDisjunction &&
!EqualIgnoringASCIICase(token.Value(), "or")))
return kInvalid;
if (range.ConsumeIncludingWhitespace().GetType() != kWhitespaceToken)
return kInvalid;
}
return result ? kSupported : kUnsupported;
}
CSSSupportsParser::SupportsResult CSSSupportsParser::ConsumeNegation(
CSSParserTokenRange range) {
DCHECK_EQ(range.Peek().GetType(), kIdentToken);
if (!EqualIgnoringASCIICase(range.Consume().Value(), "not"))
return kInvalid;
if (range.ConsumeIncludingWhitespace().GetType() != kWhitespaceToken)
return kInvalid;
SupportsResult result = ConsumeConditionInParenthesis(range);
range.ConsumeWhitespace();
if (!range.AtEnd() || result == kInvalid)
return kInvalid;
return result ? kUnsupported : kSupported;
}
CSSSupportsParser::SupportsResult
CSSSupportsParser::ConsumeConditionInParenthesis(CSSParserTokenRange& range) {
if (range.Peek().GetType() == kFunctionToken) {
range.ConsumeComponentValue();
return kUnsupported;
}
if (range.Peek().GetType() != kLeftParenthesisToken)
return kInvalid;
CSSParserTokenRange inner_range = range.ConsumeBlock();
inner_range.ConsumeWhitespace();
SupportsResult result = ConsumeCondition(inner_range);
if (result != kInvalid)
return result;
return ConsumeDeclarationCondition(inner_range);
}
CSSSupportsParser::SupportsResult
CSSSupportsParser::ConsumeDeclarationCondition(CSSParserTokenRange& range) {
if (range.Peek().GetType() != kIdentToken)
return kUnsupported;
return parser_.SupportsDeclaration(range) ? kSupported : kUnsupported;
}
} // namespace blink