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 |