| Index: third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
|
| diff --git a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
|
| index 3ee259ffbd873bef9329faaacd0d18db14a0decb..a35e46a2f0d4fd1edad08375956c10527d53ae8a 100644
|
| --- a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
|
| +++ b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
|
| @@ -8,19 +8,127 @@
|
| #include "core/css/CSSURIValue.h"
|
| #include "core/css/CSSValueList.h"
|
| #include "core/css/CSSVariableReferenceValue.h"
|
| +#include "core/css/parser/CSSParserIdioms.h"
|
| #include "core/css/parser/CSSPropertyParserHelpers.h"
|
| #include "core/css/parser/CSSTokenizer.h"
|
| #include "core/css/parser/CSSVariableParser.h"
|
| +#include "core/html/parser/HTMLParserIdioms.h"
|
|
|
| namespace blink {
|
|
|
| +void consumeWhitespace(const String& string, size_t& offset)
|
| +{
|
| + while (isHTMLSpace(string[offset]))
|
| + offset++;
|
| +}
|
| +
|
| +bool consumeCharacterAndWhitespace(const String& string, char character, size_t& offset)
|
| +{
|
| + if (string[offset] != character)
|
| + return false;
|
| + offset++;
|
| + consumeWhitespace(string, offset);
|
| + return true;
|
| +}
|
| +
|
| +CSSSyntaxType parseSyntaxType(String type)
|
| +{
|
| + // TODO(timloh): Are these supposed to be case sensitive?
|
| + if (type == "length")
|
| + return CSSSyntaxType::Length;
|
| + if (type == "number")
|
| + return CSSSyntaxType::Number;
|
| + if (type == "percentage")
|
| + return CSSSyntaxType::Percentage;
|
| + if (type == "length-percentage")
|
| + return CSSSyntaxType::LengthPercentage;
|
| + if (type == "color")
|
| + return CSSSyntaxType::Color;
|
| + if (type == "image")
|
| + return CSSSyntaxType::Image;
|
| + if (type == "url")
|
| + return CSSSyntaxType::Url;
|
| + if (type == "integer")
|
| + return CSSSyntaxType::Integer;
|
| + if (type == "angle")
|
| + return CSSSyntaxType::Angle;
|
| + if (type == "time")
|
| + return CSSSyntaxType::Time;
|
| + if (type == "resolution")
|
| + return CSSSyntaxType::Resolution;
|
| + if (type == "transform-function")
|
| + return CSSSyntaxType::TransformFunction;
|
| + if (type == "custom-ident")
|
| + return CSSSyntaxType::CustomIdent;
|
| + // Not an Ident, just used to indicate failure
|
| + return CSSSyntaxType::Ident;
|
| +}
|
| +
|
| +bool consumeSyntaxType(const String& input, size_t& offset, CSSSyntaxType& type)
|
| +{
|
| + DCHECK_EQ(input[offset], '<');
|
| + offset++;
|
| + size_t typeStart = offset;
|
| + while (offset < input.length() && input[offset] != '>')
|
| + offset++;
|
| + if (offset == input.length())
|
| + return false;
|
| + type = parseSyntaxType(input.substring(typeStart, offset - typeStart));
|
| + if (type == CSSSyntaxType::Ident)
|
| + return false;
|
| + offset++;
|
| + return true;
|
| +}
|
| +
|
| +bool consumeSyntaxIdent(const String& input, size_t& offset, String& ident)
|
| +{
|
| + // TODO(timloh): Are CSS-wide keywords allowed here?
|
| + size_t identStart = offset;
|
| + while (isNameCodePoint(input[offset]))
|
| + offset++;
|
| + if (offset == identStart)
|
| + return false;
|
| + ident = input.substring(identStart, offset - identStart);
|
| + return true;
|
| +}
|
| +
|
| CSSSyntaxDescriptor::CSSSyntaxDescriptor(String input)
|
| {
|
| - // TODO(timloh): Implement proper parsing
|
| - if (input.contains('*'))
|
| - m_syntaxComponents.append(CSSSyntaxComponent(CSSSyntaxType::TokenStream));
|
| - else
|
| - m_syntaxComponents.append(CSSSyntaxComponent(CSSSyntaxType::Length));
|
| + size_t offset = 0;
|
| + consumeWhitespace(input, offset);
|
| +
|
| + if (consumeCharacterAndWhitespace(input, '*', offset)) {
|
| + if (offset != input.length())
|
| + return;
|
| + m_syntaxComponents.append(CSSSyntaxComponent(CSSSyntaxType::TokenStream, emptyString(), false));
|
| + return;
|
| + }
|
| +
|
| + do {
|
| + CSSSyntaxType type;
|
| + String ident;
|
| + bool success;
|
| +
|
| + if (input[offset] == '<') {
|
| + success = consumeSyntaxType(input, offset, type);
|
| + } else {
|
| + type = CSSSyntaxType::Ident;
|
| + success = consumeSyntaxIdent(input, offset, ident);
|
| + }
|
| +
|
| + if (!success) {
|
| + m_syntaxComponents.clear();
|
| + return;
|
| + }
|
| +
|
| + bool repeatable = consumeCharacterAndWhitespace(input, '+', offset);
|
| + consumeWhitespace(input, offset);
|
| + m_syntaxComponents.append(CSSSyntaxComponent(type, ident, repeatable));
|
| +
|
| + } while (consumeCharacterAndWhitespace(input, '|', offset));
|
| +
|
| + if (offset != input.length())
|
| + m_syntaxComponents.clear();
|
| }
|
|
|
| const CSSValue* consumeSingleType(const CSSSyntaxComponent& syntax, CSSParserTokenRange& range)
|
| @@ -29,8 +137,40 @@ const CSSValue* consumeSingleType(const CSSSyntaxComponent& syntax, CSSParserTok
|
|
|
| // TODO(timloh): Calc values need to be normalized
|
| switch (syntax.m_type) {
|
| + case CSSSyntaxType::Ident:
|
| + if (range.peek().type() == IdentToken
|
| + && range.peek().value() == syntax.m_string) {
|
| + range.consumeIncludingWhitespace();
|
| + return CSSCustomIdentValue::create(AtomicString(syntax.m_string));
|
| + }
|
| + return nullptr;
|
| case CSSSyntaxType::Length:
|
| return consumeLength(range, HTMLStandardMode, ValueRange::ValueRangeAll);
|
| + case CSSSyntaxType::Number:
|
| + return consumeNumber(range, ValueRange::ValueRangeAll);
|
| + case CSSSyntaxType::Percentage:
|
| + return consumePercent(range, ValueRange::ValueRangeAll);
|
| + case CSSSyntaxType::LengthPercentage:
|
| + return consumeLengthOrPercent(range, HTMLStandardMode, ValueRange::ValueRangeAll);
|
| + case CSSSyntaxType::Color:
|
| + return consumeColor(range, HTMLStandardMode);
|
| + case CSSSyntaxType::Image:
|
| + // TODO(timloh): This probably needs a proper parser context for relative URL resolution.
|
| + return consumeImage(range, strictCSSParserContext());
|
| + case CSSSyntaxType::Url:
|
| + return consumeUrl(range);
|
| + case CSSSyntaxType::Integer:
|
| + return consumeInteger(range);
|
| + case CSSSyntaxType::Angle:
|
| + return consumeAngle(range);
|
| + case CSSSyntaxType::Time:
|
| + return consumeTime(range, ValueRange::ValueRangeAll);
|
| + case CSSSyntaxType::Resolution:
|
| + return nullptr; // TODO(timloh): Implement this.
|
| + case CSSSyntaxType::TransformFunction:
|
| + return nullptr; // TODO(timloh): Implement this.
|
| + case CSSSyntaxType::CustomIdent:
|
| + return consumeCustomIdent(range);
|
| default:
|
| NOTREACHED();
|
| return nullptr;
|
| @@ -40,6 +180,16 @@ const CSSValue* consumeSingleType(const CSSSyntaxComponent& syntax, CSSParserTok
|
| const CSSValue* consumeSyntaxComponent(const CSSSyntaxComponent& syntax, CSSParserTokenRange range)
|
| {
|
| // CSS-wide keywords are already handled by the CSSPropertyParser
|
| + if (syntax.m_repeatable) {
|
| + CSSValueList* list = CSSValueList::createSpaceSeparated();
|
| + while (!range.atEnd()) {
|
| + const CSSValue* value = consumeSingleType(syntax, range);
|
| + if (!value)
|
| + return nullptr;
|
| + list->append(*value);
|
| + }
|
| + return list;
|
| + }
|
| const CSSValue* result = consumeSingleType(syntax, range);
|
| if (!range.atEnd())
|
| return nullptr;
|
|
|