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