Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/css/CSSSyntaxDescriptor.h" | 5 #include "core/css/CSSSyntaxDescriptor.h" |
| 6 | 6 |
| 7 #include "core/css/CSSCustomPropertyDeclaration.h" | 7 #include "core/css/CSSCustomPropertyDeclaration.h" |
| 8 #include "core/css/CSSURIValue.h" | 8 #include "core/css/CSSURIValue.h" |
| 9 #include "core/css/CSSValueList.h" | 9 #include "core/css/CSSValueList.h" |
| 10 #include "core/css/CSSVariableReferenceValue.h" | 10 #include "core/css/CSSVariableReferenceValue.h" |
| 11 #include "core/css/parser/CSSParserIdioms.h" | |
| 11 #include "core/css/parser/CSSPropertyParserHelpers.h" | 12 #include "core/css/parser/CSSPropertyParserHelpers.h" |
| 12 #include "core/css/parser/CSSTokenizer.h" | 13 #include "core/css/parser/CSSTokenizer.h" |
| 13 #include "core/css/parser/CSSVariableParser.h" | 14 #include "core/css/parser/CSSVariableParser.h" |
| 15 #include "core/html/parser/HTMLParserIdioms.h" | |
| 14 | 16 |
| 15 namespace blink { | 17 namespace blink { |
| 16 | 18 |
| 19 void consumeWhitespace(const String& string, size_t& offset) | |
| 20 { | |
| 21 while (isHTMLSpace(string[offset])) | |
| 22 offset++; | |
| 23 } | |
| 24 | |
| 25 bool consumeCharacterAndWhitespace(const String& string, char character, size_t& offset) | |
| 26 { | |
| 27 if (string[offset] != character) | |
| 28 return false; | |
| 29 offset++; | |
| 30 consumeWhitespace(string, offset); | |
| 31 return true; | |
| 32 } | |
| 33 | |
| 34 CSSSyntaxType parseSyntaxType(String type) | |
| 35 { | |
| 36 // TODO(timloh): Are these supposed to be case sensitive? | |
| 37 if (type == "length") | |
|
meade_UTC10
2016/09/14 12:54:13
Would it be better to use a switch statement here?
Timothy Loh
2016/09/19 07:14:14
C++ doesn't support switch statements over strings
Timothy Loh
2016/09/19 07:14:42
registering a property*
| |
| 38 return CSSSyntaxType::Length; | |
| 39 if (type == "number") | |
| 40 return CSSSyntaxType::Number; | |
| 41 if (type == "percentage") | |
| 42 return CSSSyntaxType::Percentage; | |
| 43 if (type == "length-percentage") | |
| 44 return CSSSyntaxType::LengthPercentage; | |
| 45 if (type == "color") | |
| 46 return CSSSyntaxType::Color; | |
| 47 if (type == "image") | |
| 48 return CSSSyntaxType::Image; | |
| 49 if (type == "url") | |
| 50 return CSSSyntaxType::Url; | |
| 51 if (type == "integer") | |
| 52 return CSSSyntaxType::Integer; | |
| 53 if (type == "angle") | |
| 54 return CSSSyntaxType::Angle; | |
| 55 if (type == "time") | |
| 56 return CSSSyntaxType::Time; | |
| 57 if (type == "resolution") | |
| 58 return CSSSyntaxType::Resolution; | |
| 59 if (type == "transform-function") | |
| 60 return CSSSyntaxType::TransformFunction; | |
| 61 if (type == "custom-ident") | |
| 62 return CSSSyntaxType::CustomIdent; | |
| 63 // Not an Ident, just used to indicate failure | |
| 64 return CSSSyntaxType::Ident; | |
| 65 } | |
| 66 | |
| 17 CSSSyntaxDescriptor::CSSSyntaxDescriptor(String input) | 67 CSSSyntaxDescriptor::CSSSyntaxDescriptor(String input) |
| 18 { | 68 { |
| 19 // TODO(timloh): Implement proper parsing | 69 size_t offset = 0; |
| 20 if (input.contains('*')) | 70 consumeWhitespace(input, offset); |
| 21 m_syntaxComponents.append(CSSSyntaxComponent(CSSSyntaxType::TokenStream) ); | 71 |
| 22 else | 72 if (consumeCharacterAndWhitespace(input, '*', offset)) { |
| 23 m_syntaxComponents.append(CSSSyntaxComponent(CSSSyntaxType::Length)); | 73 if (offset != input.length()) |
| 74 return; | |
| 75 m_syntaxComponents.append(CSSSyntaxComponent(CSSSyntaxType::TokenStream, emptyString(), false)); | |
| 76 return; | |
| 77 } | |
| 78 | |
| 79 do { | |
| 80 CSSSyntaxType type; | |
| 81 String ident; | |
| 82 | |
| 83 if (input[offset] == '<') { | |
| 84 offset++; | |
| 85 size_t typeStart = offset; | |
| 86 while (offset < input.length() && input[offset] != '>') | |
| 87 offset++; | |
|
meade_UTC10
2016/09/14 12:54:13
This ends up with a lot of nesting, would it be cl
Timothy Loh
2016/09/19 07:14:14
I moved some of this logic into helper functions.
| |
| 88 type = parseSyntaxType(input.substring(typeStart, offset - typeStart )); | |
| 89 if (offset == input.length() || type == CSSSyntaxType::Ident) { | |
| 90 m_syntaxComponents.clear(); | |
| 91 return; | |
| 92 } | |
| 93 offset++; | |
| 94 } else { | |
| 95 // TODO(timloh): Are CSS-wide keywords allowed here? | |
| 96 size_t identStart = offset; | |
| 97 while (isNameCodePoint(input[offset])) | |
| 98 offset++; | |
| 99 if (offset == identStart) { | |
| 100 m_syntaxComponents.clear(); | |
| 101 return; | |
| 102 } | |
| 103 type = CSSSyntaxType::Ident; | |
| 104 ident = input.substring(identStart, offset - identStart); | |
| 105 } | |
| 106 | |
| 107 bool repeatable = consumeCharacterAndWhitespace(input, '+', offset); | |
| 108 consumeWhitespace(input, offset); | |
| 109 m_syntaxComponents.append(CSSSyntaxComponent(type, ident, repeatable)); | |
| 110 | |
| 111 } while (consumeCharacterAndWhitespace(input, '|', offset)); | |
| 112 | |
| 113 if (offset != input.length()) | |
| 114 m_syntaxComponents.clear(); | |
| 24 } | 115 } |
| 25 | 116 |
| 26 const CSSValue* consumeSingleType(const CSSSyntaxComponent& syntax, CSSParserTok enRange& range) | 117 const CSSValue* consumeSingleType(const CSSSyntaxComponent& syntax, CSSParserTok enRange& range) |
| 27 { | 118 { |
| 28 using namespace CSSPropertyParserHelpers; | 119 using namespace CSSPropertyParserHelpers; |
| 29 | 120 |
| 30 // TODO(timloh): Calc values need to be normalized | 121 // TODO(timloh): Calc values need to be normalized |
| 31 switch (syntax.m_type) { | 122 switch (syntax.m_type) { |
| 123 case CSSSyntaxType::Ident: | |
| 124 if (range.peek().type() == IdentToken | |
| 125 && range.peek().value() == syntax.m_string) { | |
| 126 range.consumeIncludingWhitespace(); | |
| 127 return CSSCustomIdentValue::create(AtomicString(syntax.m_string)); | |
| 128 } | |
| 129 return nullptr; | |
| 32 case CSSSyntaxType::Length: | 130 case CSSSyntaxType::Length: |
| 33 return consumeLength(range, HTMLStandardMode, ValueRange::ValueRangeAll) ; | 131 return consumeLength(range, HTMLStandardMode, ValueRange::ValueRangeAll) ; |
| 132 case CSSSyntaxType::Number: | |
| 133 return consumeNumber(range, ValueRange::ValueRangeAll); | |
| 134 case CSSSyntaxType::Percentage: | |
| 135 return consumePercent(range, ValueRange::ValueRangeAll); | |
| 136 case CSSSyntaxType::LengthPercentage: | |
| 137 return consumeLengthOrPercent(range, HTMLStandardMode, ValueRange::Value RangeAll); | |
| 138 case CSSSyntaxType::Color: | |
| 139 return consumeColor(range, HTMLStandardMode); | |
| 140 case CSSSyntaxType::Image: | |
| 141 // TODO(timloh): This probably needs a proper parser context for relativ e URL resolution. | |
| 142 return consumeImage(range, strictCSSParserContext()); | |
| 143 case CSSSyntaxType::Url: | |
| 144 return consumeUrl(range); | |
| 145 case CSSSyntaxType::Integer: | |
| 146 return consumeInteger(range); | |
| 147 case CSSSyntaxType::Angle: | |
| 148 return consumeAngle(range); | |
| 149 case CSSSyntaxType::Time: | |
| 150 return consumeTime(range, ValueRange::ValueRangeAll); | |
| 151 case CSSSyntaxType::Resolution: | |
| 152 return nullptr; // TODO(timloh): Implement this. | |
| 153 case CSSSyntaxType::TransformFunction: | |
| 154 return nullptr; // TODO(timloh): Implement this. | |
| 155 case CSSSyntaxType::CustomIdent: | |
| 156 return consumeCustomIdent(range); | |
| 34 default: | 157 default: |
| 35 NOTREACHED(); | 158 NOTREACHED(); |
| 36 return nullptr; | 159 return nullptr; |
| 37 } | 160 } |
| 38 } | 161 } |
| 39 | 162 |
| 40 const CSSValue* consumeSyntaxComponent(const CSSSyntaxComponent& syntax, CSSPars erTokenRange range) | 163 const CSSValue* consumeSyntaxComponent(const CSSSyntaxComponent& syntax, CSSPars erTokenRange range) |
| 41 { | 164 { |
| 42 // CSS-wide keywords are already handled by the CSSPropertyParser | 165 // CSS-wide keywords are already handled by the CSSPropertyParser |
| 166 if (syntax.m_repeatable) { | |
| 167 CSSValueList* list = CSSValueList::createSpaceSeparated(); | |
| 168 while (!range.atEnd()) { | |
| 169 const CSSValue* value = consumeSingleType(syntax, range); | |
| 170 if (!value) | |
| 171 return nullptr; | |
| 172 list->append(*value); | |
| 173 } | |
| 174 return list; | |
| 175 } | |
| 43 const CSSValue* result = consumeSingleType(syntax, range); | 176 const CSSValue* result = consumeSingleType(syntax, range); |
| 44 if (!range.atEnd()) | 177 if (!range.atEnd()) |
| 45 return nullptr; | 178 return nullptr; |
| 46 return result; | 179 return result; |
| 47 } | 180 } |
| 48 | 181 |
| 49 const CSSValue* CSSSyntaxDescriptor::parse(const String& value) const | 182 const CSSValue* CSSSyntaxDescriptor::parse(const String& value) const |
| 50 { | 183 { |
| 51 CSSTokenizer::Scope scope(value); | 184 CSSTokenizer::Scope scope(value); |
| 52 return parse(scope.tokenRange()); | 185 return parse(scope.tokenRange()); |
| 53 } | 186 } |
| 54 | 187 |
| 55 const CSSValue* CSSSyntaxDescriptor::parse(CSSParserTokenRange range) const | 188 const CSSValue* CSSSyntaxDescriptor::parse(CSSParserTokenRange range) const |
| 56 { | 189 { |
| 57 if (isTokenStream()) | 190 if (isTokenStream()) |
| 58 return CSSVariableParser::parseRegisteredPropertyValue(range, false); | 191 return CSSVariableParser::parseRegisteredPropertyValue(range, false); |
| 59 range.consumeWhitespace(); | 192 range.consumeWhitespace(); |
| 60 for (const CSSSyntaxComponent& component : m_syntaxComponents) { | 193 for (const CSSSyntaxComponent& component : m_syntaxComponents) { |
| 61 if (const CSSValue* result = consumeSyntaxComponent(component, range)) | 194 if (const CSSValue* result = consumeSyntaxComponent(component, range)) |
| 62 return result; | 195 return result; |
| 63 } | 196 } |
| 64 return CSSVariableParser::parseRegisteredPropertyValue(range, true); | 197 return CSSVariableParser::parseRegisteredPropertyValue(range, true); |
| 65 } | 198 } |
| 66 | 199 |
| 67 } // namespace blink | 200 } // namespace blink |
| OLD | NEW |