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; |