OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/resolver/CSSVariableResolver.h" | 5 #include "core/css/resolver/CSSVariableResolver.h" |
6 | 6 |
7 #include "core/CSSPropertyNames.h" | 7 #include "core/CSSPropertyNames.h" |
8 #include "core/CSSValueKeywords.h" | 8 #include "core/CSSValueKeywords.h" |
9 #include "core/StyleBuilderFunctions.h" | 9 #include "core/StyleBuilderFunctions.h" |
10 #include "core/StylePropertyShorthand.h" | 10 #include "core/StylePropertyShorthand.h" |
11 #include "core/css/CSSPendingSubstitutionValue.h" | 11 #include "core/css/CSSPendingSubstitutionValue.h" |
12 #include "core/css/CSSUnsetValue.h" | 12 #include "core/css/CSSUnsetValue.h" |
13 #include "core/css/CSSVariableData.h" | 13 #include "core/css/CSSVariableData.h" |
14 #include "core/css/CSSVariableReferenceValue.h" | 14 #include "core/css/CSSVariableReferenceValue.h" |
15 #include "core/css/PropertyRegistry.h" | 15 #include "core/css/PropertyRegistry.h" |
16 #include "core/css/parser/CSSParserToken.h" | 16 #include "core/css/parser/CSSParserToken.h" |
17 #include "core/css/parser/CSSParserTokenRange.h" | 17 #include "core/css/parser/CSSParserTokenRange.h" |
18 #include "core/css/parser/CSSPropertyParser.h" | 18 #include "core/css/parser/CSSPropertyParser.h" |
19 #include "core/css/resolver/StyleBuilder.h" | 19 #include "core/css/resolver/StyleBuilder.h" |
20 #include "core/css/resolver/StyleBuilderConverter.h" | 20 #include "core/css/resolver/StyleBuilderConverter.h" |
21 #include "core/css/resolver/StyleResolverState.h" | 21 #include "core/css/resolver/StyleResolverState.h" |
22 #include "core/css/resolver/StyleResolverStats.h" | 22 #include "core/css/resolver/StyleResolverStats.h" |
23 #include "core/dom/StyleEngine.h" | 23 #include "core/dom/StyleEngine.h" |
24 #include "core/style/StyleInheritedVariables.h" | 24 #include "core/style/StyleInheritedVariables.h" |
25 #include "core/style/StyleNonInheritedVariables.h" | 25 #include "core/style/StyleNonInheritedVariables.h" |
26 #include "platform/wtf/Vector.h" | 26 #include "platform/wtf/Vector.h" |
27 | 27 |
28 namespace blink { | 28 namespace blink { |
29 | 29 |
30 bool CSSVariableResolver::ResolveFallback(CSSParserTokenRange range, | 30 bool CSSVariableResolver::ResolveFallback( |
31 bool disallow_animation_tainted, | 31 CSSParserTokenRange range, |
32 Vector<CSSParserToken>& result, | 32 bool disallow_animation_tainted, |
33 bool& result_is_animation_tainted) { | 33 Vector<CSSParserToken>& result, |
| 34 Vector<String>& result_backing_strings, |
| 35 bool& result_is_animation_tainted) { |
34 if (range.AtEnd()) | 36 if (range.AtEnd()) |
35 return false; | 37 return false; |
36 DCHECK_EQ(range.Peek().GetType(), kCommaToken); | 38 DCHECK_EQ(range.Peek().GetType(), kCommaToken); |
37 range.Consume(); | 39 range.Consume(); |
38 return ResolveTokenRange(range, disallow_animation_tainted, result, | 40 return ResolveTokenRange(range, disallow_animation_tainted, result, |
39 result_is_animation_tainted); | 41 result_backing_strings, result_is_animation_tainted); |
40 } | 42 } |
41 | 43 |
42 CSSVariableData* CSSVariableResolver::ValueForCustomProperty( | 44 CSSVariableData* CSSVariableResolver::ValueForCustomProperty( |
43 AtomicString name) { | 45 AtomicString name) { |
44 if (variables_seen_.Contains(name)) { | 46 if (variables_seen_.Contains(name)) { |
45 cycle_start_points_.insert(name); | 47 cycle_start_points_.insert(name); |
46 return nullptr; | 48 return nullptr; |
47 } | 49 } |
48 | 50 |
49 DCHECK(registry_ || !RuntimeEnabledFeatures::cssVariables2Enabled()); | 51 DCHECK(registry_ || !RuntimeEnabledFeatures::cssVariables2Enabled()); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 } | 91 } |
90 | 92 |
91 PassRefPtr<CSSVariableData> CSSVariableResolver::ResolveCustomProperty( | 93 PassRefPtr<CSSVariableData> CSSVariableResolver::ResolveCustomProperty( |
92 AtomicString name, | 94 AtomicString name, |
93 const CSSVariableData& variable_data) { | 95 const CSSVariableData& variable_data) { |
94 DCHECK(variable_data.NeedsVariableResolution()); | 96 DCHECK(variable_data.NeedsVariableResolution()); |
95 | 97 |
96 bool disallow_animation_tainted = false; | 98 bool disallow_animation_tainted = false; |
97 bool is_animation_tainted = variable_data.IsAnimationTainted(); | 99 bool is_animation_tainted = variable_data.IsAnimationTainted(); |
98 Vector<CSSParserToken> tokens; | 100 Vector<CSSParserToken> tokens; |
| 101 Vector<String> backing_strings; |
| 102 backing_strings.AppendVector(variable_data.BackingStrings()); |
99 variables_seen_.insert(name); | 103 variables_seen_.insert(name); |
100 bool success = | 104 bool success = |
101 ResolveTokenRange(variable_data.Tokens(), disallow_animation_tainted, | 105 ResolveTokenRange(variable_data.Tokens(), disallow_animation_tainted, |
102 tokens, is_animation_tainted); | 106 tokens, backing_strings, is_animation_tainted); |
103 variables_seen_.erase(name); | 107 variables_seen_.erase(name); |
104 | 108 |
105 // The old variable data holds onto the backing string the new resolved | |
106 // CSSVariableData relies on. Ensure it will live beyond us overwriting the | |
107 // RefPtr in StyleInheritedVariables. | |
108 DCHECK_GT(variable_data.RefCount(), 1); | |
109 | |
110 if (!success || !cycle_start_points_.IsEmpty()) { | 109 if (!success || !cycle_start_points_.IsEmpty()) { |
111 cycle_start_points_.erase(name); | 110 cycle_start_points_.erase(name); |
112 return nullptr; | 111 return nullptr; |
113 } | 112 } |
114 return CSSVariableData::CreateResolved(tokens, variable_data, | 113 return CSSVariableData::CreateResolved(tokens, std::move(backing_strings), |
115 is_animation_tainted); | 114 is_animation_tainted); |
116 } | 115 } |
117 | 116 |
118 bool CSSVariableResolver::ResolveVariableReference( | 117 bool CSSVariableResolver::ResolveVariableReference( |
119 CSSParserTokenRange range, | 118 CSSParserTokenRange range, |
120 bool disallow_animation_tainted, | 119 bool disallow_animation_tainted, |
121 Vector<CSSParserToken>& result, | 120 Vector<CSSParserToken>& result, |
| 121 Vector<String>& result_backing_strings, |
122 bool& result_is_animation_tainted) { | 122 bool& result_is_animation_tainted) { |
123 range.ConsumeWhitespace(); | 123 range.ConsumeWhitespace(); |
124 DCHECK_EQ(range.Peek().GetType(), kIdentToken); | 124 DCHECK_EQ(range.Peek().GetType(), kIdentToken); |
125 AtomicString variable_name = | 125 AtomicString variable_name = |
126 range.ConsumeIncludingWhitespace().Value().ToAtomicString(); | 126 range.ConsumeIncludingWhitespace().Value().ToAtomicString(); |
127 DCHECK(range.AtEnd() || (range.Peek().GetType() == kCommaToken)); | 127 DCHECK(range.AtEnd() || (range.Peek().GetType() == kCommaToken)); |
128 | 128 |
129 CSSVariableData* variable_data = ValueForCustomProperty(variable_name); | 129 CSSVariableData* variable_data = ValueForCustomProperty(variable_name); |
130 if (!variable_data || | 130 if (!variable_data || |
131 (disallow_animation_tainted && variable_data->IsAnimationTainted())) { | 131 (disallow_animation_tainted && variable_data->IsAnimationTainted())) { |
132 // TODO(alancutter): Append the registered initial custom property value if | 132 // TODO(alancutter): Append the registered initial custom property value if |
133 // we are disallowing an animation tainted value. | 133 // we are disallowing an animation tainted value. |
134 return ResolveFallback(range, disallow_animation_tainted, result, | 134 return ResolveFallback(range, disallow_animation_tainted, result, |
135 result_is_animation_tainted); | 135 result_backing_strings, result_is_animation_tainted); |
136 } | 136 } |
137 | 137 |
138 result.AppendVector(variable_data->Tokens()); | 138 result.AppendVector(variable_data->Tokens()); |
| 139 // TODO(alancutter): Avoid adding backing strings multiple times in a row. |
| 140 result_backing_strings.AppendVector(variable_data->BackingStrings()); |
139 result_is_animation_tainted |= variable_data->IsAnimationTainted(); | 141 result_is_animation_tainted |= variable_data->IsAnimationTainted(); |
140 | 142 |
141 Vector<CSSParserToken> trash; | 143 Vector<CSSParserToken> trash; |
| 144 Vector<String> trash_backing_strings; |
142 bool trash_is_animation_tainted; | 145 bool trash_is_animation_tainted; |
143 ResolveFallback(range, disallow_animation_tainted, trash, | 146 ResolveFallback(range, disallow_animation_tainted, trash, |
144 trash_is_animation_tainted); | 147 trash_backing_strings, trash_is_animation_tainted); |
145 return true; | 148 return true; |
146 } | 149 } |
147 | 150 |
148 void CSSVariableResolver::ResolveApplyAtRule(CSSParserTokenRange& range, | 151 void CSSVariableResolver::ResolveApplyAtRule( |
149 Vector<CSSParserToken>& result) { | 152 CSSParserTokenRange& range, |
| 153 Vector<CSSParserToken>& result, |
| 154 Vector<String>& result_backing_strings) { |
150 DCHECK(range.Peek().GetType() == kAtKeywordToken && | 155 DCHECK(range.Peek().GetType() == kAtKeywordToken && |
151 EqualIgnoringASCIICase(range.Peek().Value(), "apply")); | 156 EqualIgnoringASCIICase(range.Peek().Value(), "apply")); |
152 range.ConsumeIncludingWhitespace(); | 157 range.ConsumeIncludingWhitespace(); |
153 const CSSParserToken& variable_name = range.ConsumeIncludingWhitespace(); | 158 const CSSParserToken& variable_name = range.ConsumeIncludingWhitespace(); |
154 // TODO(timloh): Should we actually be consuming this? | 159 // TODO(timloh): Should we actually be consuming this? |
155 if (range.Peek().GetType() == kSemicolonToken) | 160 if (range.Peek().GetType() == kSemicolonToken) |
156 range.Consume(); | 161 range.Consume(); |
157 | 162 |
158 CSSVariableData* variable_data = | 163 CSSVariableData* variable_data = |
159 ValueForCustomProperty(variable_name.Value().ToAtomicString()); | 164 ValueForCustomProperty(variable_name.Value().ToAtomicString()); |
160 if (!variable_data) | 165 if (!variable_data) |
161 return; // Invalid custom property | 166 return; // Invalid custom property |
162 | 167 |
163 CSSParserTokenRange rule = variable_data->TokenRange(); | 168 CSSParserTokenRange rule = variable_data->TokenRange(); |
164 rule.ConsumeWhitespace(); | 169 rule.ConsumeWhitespace(); |
165 if (rule.Peek().GetType() != kLeftBraceToken) | 170 if (rule.Peek().GetType() != kLeftBraceToken) |
166 return; | 171 return; |
167 CSSParserTokenRange rule_contents = rule.ConsumeBlock(); | 172 CSSParserTokenRange rule_contents = rule.ConsumeBlock(); |
168 rule.ConsumeWhitespace(); | 173 rule.ConsumeWhitespace(); |
169 if (!rule.AtEnd()) | 174 if (!rule.AtEnd()) |
170 return; | 175 return; |
171 | 176 |
172 result.AppendRange(rule_contents.begin(), rule_contents.end()); | 177 result.AppendRange(rule_contents.begin(), rule_contents.end()); |
| 178 result_backing_strings.AppendVector(variable_data->BackingStrings()); |
173 } | 179 } |
174 | 180 |
175 bool CSSVariableResolver::ResolveTokenRange(CSSParserTokenRange range, | 181 bool CSSVariableResolver::ResolveTokenRange( |
176 bool disallow_animation_tainted, | 182 CSSParserTokenRange range, |
177 Vector<CSSParserToken>& result, | 183 bool disallow_animation_tainted, |
178 bool& result_is_animation_tainted) { | 184 Vector<CSSParserToken>& result, |
| 185 Vector<String>& result_backing_strings, |
| 186 bool& result_is_animation_tainted) { |
179 bool success = true; | 187 bool success = true; |
180 while (!range.AtEnd()) { | 188 while (!range.AtEnd()) { |
181 if (range.Peek().FunctionId() == CSSValueVar) { | 189 if (range.Peek().FunctionId() == CSSValueVar) { |
182 success &= ResolveVariableReference(range.ConsumeBlock(), | 190 success &= ResolveVariableReference( |
183 disallow_animation_tainted, result, | 191 range.ConsumeBlock(), disallow_animation_tainted, result, |
184 result_is_animation_tainted); | 192 result_backing_strings, result_is_animation_tainted); |
185 } else if (range.Peek().GetType() == kAtKeywordToken && | 193 } else if (range.Peek().GetType() == kAtKeywordToken && |
186 EqualIgnoringASCIICase(range.Peek().Value(), "apply") && | 194 EqualIgnoringASCIICase(range.Peek().Value(), "apply") && |
187 RuntimeEnabledFeatures::cssApplyAtRulesEnabled()) { | 195 RuntimeEnabledFeatures::cssApplyAtRulesEnabled()) { |
188 ResolveApplyAtRule(range, result); | 196 ResolveApplyAtRule(range, result, result_backing_strings); |
189 } else { | 197 } else { |
190 result.push_back(range.Consume()); | 198 result.push_back(range.Consume()); |
191 } | 199 } |
192 } | 200 } |
193 return success; | 201 return success; |
194 } | 202 } |
195 | 203 |
196 const CSSValue* CSSVariableResolver::ResolveVariableReferences( | 204 const CSSValue* CSSVariableResolver::ResolveVariableReferences( |
197 const StyleResolverState& state, | 205 const StyleResolverState& state, |
198 CSSPropertyID id, | 206 CSSPropertyID id, |
(...skipping 17 matching lines...) Expand all Loading... |
216 return nullptr; | 224 return nullptr; |
217 } | 225 } |
218 | 226 |
219 const CSSValue* CSSVariableResolver::ResolveVariableReferences( | 227 const CSSValue* CSSVariableResolver::ResolveVariableReferences( |
220 const StyleResolverState& state, | 228 const StyleResolverState& state, |
221 CSSPropertyID id, | 229 CSSPropertyID id, |
222 const CSSVariableReferenceValue& value, | 230 const CSSVariableReferenceValue& value, |
223 bool disallow_animation_tainted) { | 231 bool disallow_animation_tainted) { |
224 CSSVariableResolver resolver(state); | 232 CSSVariableResolver resolver(state); |
225 Vector<CSSParserToken> tokens; | 233 Vector<CSSParserToken> tokens; |
| 234 Vector<String> backing_strings; |
226 bool is_animation_tainted = false; | 235 bool is_animation_tainted = false; |
227 if (!resolver.ResolveTokenRange(value.VariableDataValue()->Tokens(), | 236 if (!resolver.ResolveTokenRange(value.VariableDataValue()->Tokens(), |
228 disallow_animation_tainted, tokens, | 237 disallow_animation_tainted, tokens, |
229 is_animation_tainted)) | 238 backing_strings, is_animation_tainted)) |
230 return CSSUnsetValue::Create(); | 239 return CSSUnsetValue::Create(); |
231 const CSSValue* result = | 240 const CSSValue* result = |
232 CSSPropertyParser::ParseSingleValue(id, tokens, value.ParserContext()); | 241 CSSPropertyParser::ParseSingleValue(id, tokens, value.ParserContext()); |
233 if (!result) | 242 if (!result) |
234 return CSSUnsetValue::Create(); | 243 return CSSUnsetValue::Create(); |
235 return result; | 244 return result; |
236 } | 245 } |
237 | 246 |
238 const CSSValue* CSSVariableResolver::ResolvePendingSubstitutions( | 247 const CSSValue* CSSVariableResolver::ResolvePendingSubstitutions( |
239 const StyleResolverState& state, | 248 const StyleResolverState& state, |
240 CSSPropertyID id, | 249 CSSPropertyID id, |
241 const CSSPendingSubstitutionValue& pending_value, | 250 const CSSPendingSubstitutionValue& pending_value, |
242 bool disallow_animation_tainted) { | 251 bool disallow_animation_tainted) { |
243 // Longhands from shorthand references follow this path. | 252 // Longhands from shorthand references follow this path. |
244 HeapHashMap<CSSPropertyID, Member<const CSSValue>>& property_cache = | 253 HeapHashMap<CSSPropertyID, Member<const CSSValue>>& property_cache = |
245 state.ParsedPropertiesForPendingSubstitutionCache(pending_value); | 254 state.ParsedPropertiesForPendingSubstitutionCache(pending_value); |
246 | 255 |
247 const CSSValue* value = property_cache.at(id); | 256 const CSSValue* value = property_cache.at(id); |
248 if (!value) { | 257 if (!value) { |
249 // TODO(timloh): We shouldn't retry this for all longhands if the shorthand | 258 // TODO(timloh): We shouldn't retry this for all longhands if the shorthand |
250 // ends up invalid. | 259 // ends up invalid. |
251 CSSVariableReferenceValue* shorthand_value = pending_value.ShorthandValue(); | 260 CSSVariableReferenceValue* shorthand_value = pending_value.ShorthandValue(); |
252 CSSPropertyID shorthand_property_id = pending_value.ShorthandPropertyId(); | 261 CSSPropertyID shorthand_property_id = pending_value.ShorthandPropertyId(); |
253 | 262 |
254 CSSVariableResolver resolver(state); | 263 CSSVariableResolver resolver(state); |
255 | 264 |
256 Vector<CSSParserToken> tokens; | 265 Vector<CSSParserToken> tokens; |
| 266 Vector<String> backing_strings; |
257 bool is_animation_tainted = false; | 267 bool is_animation_tainted = false; |
258 if (resolver.ResolveTokenRange( | 268 if (resolver.ResolveTokenRange( |
259 shorthand_value->VariableDataValue()->Tokens(), | 269 shorthand_value->VariableDataValue()->Tokens(), |
260 disallow_animation_tainted, tokens, is_animation_tainted)) { | 270 disallow_animation_tainted, tokens, backing_strings, |
261 | 271 is_animation_tainted)) { |
262 HeapVector<CSSProperty, 256> parsed_properties; | 272 HeapVector<CSSProperty, 256> parsed_properties; |
263 | 273 |
264 if (CSSPropertyParser::ParseValue( | 274 if (CSSPropertyParser::ParseValue( |
265 shorthand_property_id, false, CSSParserTokenRange(tokens), | 275 shorthand_property_id, false, CSSParserTokenRange(tokens), |
266 shorthand_value->ParserContext(), parsed_properties, | 276 shorthand_value->ParserContext(), parsed_properties, |
267 StyleRule::RuleType::kStyle)) { | 277 StyleRule::RuleType::kStyle)) { |
268 unsigned parsed_properties_count = parsed_properties.size(); | 278 unsigned parsed_properties_count = parsed_properties.size(); |
269 for (unsigned i = 0; i < parsed_properties_count; ++i) { | 279 for (unsigned i = 0; i < parsed_properties_count; ++i) { |
270 property_cache.Set(parsed_properties[i].Id(), | 280 property_cache.Set(parsed_properties[i].Id(), |
271 parsed_properties[i].Value()); | 281 parsed_properties[i].Value()); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
334 } | 344 } |
335 } | 345 } |
336 } | 346 } |
337 | 347 |
338 CSSVariableResolver::CSSVariableResolver(const StyleResolverState& state) | 348 CSSVariableResolver::CSSVariableResolver(const StyleResolverState& state) |
339 : inherited_variables_(state.Style()->InheritedVariables()), | 349 : inherited_variables_(state.Style()->InheritedVariables()), |
340 non_inherited_variables_(state.Style()->NonInheritedVariables()), | 350 non_inherited_variables_(state.Style()->NonInheritedVariables()), |
341 registry_(state.GetDocument().GetPropertyRegistry()) {} | 351 registry_(state.GetDocument().GetPropertyRegistry()) {} |
342 | 352 |
343 } // namespace blink | 353 } // namespace blink |
OLD | NEW |