| 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/style/StyleInheritedVariables.h" | 22 #include "core/style/StyleInheritedVariables.h" |
| 23 #include "core/style/StyleNonInheritedVariables.h" | 23 #include "core/style/StyleNonInheritedVariables.h" |
| 24 #include "wtf/Vector.h" | 24 #include "wtf/Vector.h" |
| 25 | 25 |
| 26 namespace blink { | 26 namespace blink { |
| 27 | 27 |
| 28 bool CSSVariableResolver::resolveFallback(CSSParserTokenRange range, | 28 bool CSSVariableResolver::resolveFallback(CSSParserTokenRange range, |
| 29 Vector<CSSParserToken>& result) { | 29 bool disallowAnimationTainted, |
| 30 Vector<CSSParserToken>& result, |
| 31 bool& resultIsAnimationTainted) { |
| 30 if (range.atEnd()) | 32 if (range.atEnd()) |
| 31 return false; | 33 return false; |
| 32 ASSERT(range.peek().type() == CommaToken); | 34 ASSERT(range.peek().type() == CommaToken); |
| 33 range.consume(); | 35 range.consume(); |
| 34 return resolveTokenRange(range, result); | 36 return resolveTokenRange(range, disallowAnimationTainted, result, |
| 37 resultIsAnimationTainted); |
| 35 } | 38 } |
| 36 | 39 |
| 37 CSSVariableData* CSSVariableResolver::valueForCustomProperty( | 40 CSSVariableData* CSSVariableResolver::valueForCustomProperty( |
| 38 AtomicString name) { | 41 AtomicString name) { |
| 39 if (m_variablesSeen.contains(name)) { | 42 if (m_variablesSeen.contains(name)) { |
| 40 m_cycleStartPoints.add(name); | 43 m_cycleStartPoints.add(name); |
| 41 return nullptr; | 44 return nullptr; |
| 42 } | 45 } |
| 43 | 46 |
| 44 DCHECK(m_registry || !RuntimeEnabledFeatures::cssVariables2Enabled()); | 47 DCHECK(m_registry || !RuntimeEnabledFeatures::cssVariables2Enabled()); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 if (!newVariableData) | 86 if (!newVariableData) |
| 84 return registration->initialVariableData(); | 87 return registration->initialVariableData(); |
| 85 return newVariableData.get(); | 88 return newVariableData.get(); |
| 86 } | 89 } |
| 87 | 90 |
| 88 PassRefPtr<CSSVariableData> CSSVariableResolver::resolveCustomProperty( | 91 PassRefPtr<CSSVariableData> CSSVariableResolver::resolveCustomProperty( |
| 89 AtomicString name, | 92 AtomicString name, |
| 90 const CSSVariableData& variableData) { | 93 const CSSVariableData& variableData) { |
| 91 ASSERT(variableData.needsVariableResolution()); | 94 ASSERT(variableData.needsVariableResolution()); |
| 92 | 95 |
| 96 bool disallowAnimationTainted = false; |
| 97 bool isAnimationTainted = variableData.isAnimationTainted(); |
| 93 Vector<CSSParserToken> tokens; | 98 Vector<CSSParserToken> tokens; |
| 94 m_variablesSeen.add(name); | 99 m_variablesSeen.add(name); |
| 95 bool success = resolveTokenRange(variableData.tokens(), tokens); | 100 bool success = |
| 101 resolveTokenRange(variableData.tokens(), disallowAnimationTainted, tokens, |
| 102 isAnimationTainted); |
| 96 m_variablesSeen.remove(name); | 103 m_variablesSeen.remove(name); |
| 97 | 104 |
| 98 // The old variable data holds onto the backing string the new resolved | 105 // The old variable data holds onto the backing string the new resolved |
| 99 // CSSVariableData relies on. Ensure it will live beyond us overwriting the | 106 // CSSVariableData relies on. Ensure it will live beyond us overwriting the |
| 100 // RefPtr in StyleInheritedVariables. | 107 // RefPtr in StyleInheritedVariables. |
| 101 ASSERT(variableData.refCount() > 1); | 108 ASSERT(variableData.refCount() > 1); |
| 102 | 109 |
| 103 if (!success || !m_cycleStartPoints.isEmpty()) { | 110 if (!success || !m_cycleStartPoints.isEmpty()) { |
| 104 m_cycleStartPoints.remove(name); | 111 m_cycleStartPoints.remove(name); |
| 105 return nullptr; | 112 return nullptr; |
| 106 } | 113 } |
| 107 return CSSVariableData::createResolved(tokens, variableData); | 114 return CSSVariableData::createResolved(tokens, variableData, |
| 115 isAnimationTainted); |
| 108 } | 116 } |
| 109 | 117 |
| 110 bool CSSVariableResolver::resolveVariableReference( | 118 bool CSSVariableResolver::resolveVariableReference( |
| 111 CSSParserTokenRange range, | 119 CSSParserTokenRange range, |
| 112 Vector<CSSParserToken>& result) { | 120 bool disallowAnimationTainted, |
| 121 Vector<CSSParserToken>& result, |
| 122 bool& resultIsAnimationTainted) { |
| 113 range.consumeWhitespace(); | 123 range.consumeWhitespace(); |
| 114 ASSERT(range.peek().type() == IdentToken); | 124 ASSERT(range.peek().type() == IdentToken); |
| 115 AtomicString variableName = | 125 AtomicString variableName = |
| 116 range.consumeIncludingWhitespace().value().toAtomicString(); | 126 range.consumeIncludingWhitespace().value().toAtomicString(); |
| 117 ASSERT(range.atEnd() || (range.peek().type() == CommaToken)); | 127 ASSERT(range.atEnd() || (range.peek().type() == CommaToken)); |
| 118 | 128 |
| 119 CSSVariableData* variableData = valueForCustomProperty(variableName); | 129 CSSVariableData* variableData = valueForCustomProperty(variableName); |
| 120 if (!variableData) | 130 if (!variableData || |
| 121 return resolveFallback(range, result); | 131 (disallowAnimationTainted && variableData->isAnimationTainted())) { |
| 132 // TODO(alancutter): Append the registered initial custom property value if |
| 133 // we are disallowing an animation tainted value. |
| 134 return resolveFallback(range, disallowAnimationTainted, result, |
| 135 resultIsAnimationTainted); |
| 136 } |
| 122 | 137 |
| 123 result.appendVector(variableData->tokens()); | 138 result.appendVector(variableData->tokens()); |
| 139 resultIsAnimationTainted |= variableData->isAnimationTainted(); |
| 140 |
| 124 Vector<CSSParserToken> trash; | 141 Vector<CSSParserToken> trash; |
| 125 resolveFallback(range, trash); | 142 bool trashIsAnimationTainted; |
| 143 resolveFallback(range, disallowAnimationTainted, trash, |
| 144 trashIsAnimationTainted); |
| 126 return true; | 145 return true; |
| 127 } | 146 } |
| 128 | 147 |
| 129 void CSSVariableResolver::resolveApplyAtRule(CSSParserTokenRange& range, | 148 void CSSVariableResolver::resolveApplyAtRule(CSSParserTokenRange& range, |
| 130 Vector<CSSParserToken>& result) { | 149 Vector<CSSParserToken>& result) { |
| 131 DCHECK(range.peek().type() == AtKeywordToken && | 150 DCHECK(range.peek().type() == AtKeywordToken && |
| 132 equalIgnoringASCIICase(range.peek().value(), "apply")); | 151 equalIgnoringASCIICase(range.peek().value(), "apply")); |
| 133 range.consumeIncludingWhitespace(); | 152 range.consumeIncludingWhitespace(); |
| 134 const CSSParserToken& variableName = range.consumeIncludingWhitespace(); | 153 const CSSParserToken& variableName = range.consumeIncludingWhitespace(); |
| 135 // TODO(timloh): Should we actually be consuming this? | 154 // TODO(timloh): Should we actually be consuming this? |
| (...skipping 11 matching lines...) Expand all Loading... |
| 147 return; | 166 return; |
| 148 CSSParserTokenRange ruleContents = rule.consumeBlock(); | 167 CSSParserTokenRange ruleContents = rule.consumeBlock(); |
| 149 rule.consumeWhitespace(); | 168 rule.consumeWhitespace(); |
| 150 if (!rule.atEnd()) | 169 if (!rule.atEnd()) |
| 151 return; | 170 return; |
| 152 | 171 |
| 153 result.appendRange(ruleContents.begin(), ruleContents.end()); | 172 result.appendRange(ruleContents.begin(), ruleContents.end()); |
| 154 } | 173 } |
| 155 | 174 |
| 156 bool CSSVariableResolver::resolveTokenRange(CSSParserTokenRange range, | 175 bool CSSVariableResolver::resolveTokenRange(CSSParserTokenRange range, |
| 157 Vector<CSSParserToken>& result) { | 176 bool disallowAnimationTainted, |
| 177 Vector<CSSParserToken>& result, |
| 178 bool& resultIsAnimationTainted) { |
| 158 bool success = true; | 179 bool success = true; |
| 159 while (!range.atEnd()) { | 180 while (!range.atEnd()) { |
| 160 if (range.peek().functionId() == CSSValueVar) { | 181 if (range.peek().functionId() == CSSValueVar) { |
| 161 success &= resolveVariableReference(range.consumeBlock(), result); | 182 success &= resolveVariableReference(range.consumeBlock(), |
| 183 disallowAnimationTainted, result, |
| 184 resultIsAnimationTainted); |
| 162 } else if (range.peek().type() == AtKeywordToken && | 185 } else if (range.peek().type() == AtKeywordToken && |
| 163 equalIgnoringASCIICase(range.peek().value(), "apply") && | 186 equalIgnoringASCIICase(range.peek().value(), "apply") && |
| 164 RuntimeEnabledFeatures::cssApplyAtRulesEnabled()) { | 187 RuntimeEnabledFeatures::cssApplyAtRulesEnabled()) { |
| 165 resolveApplyAtRule(range, result); | 188 resolveApplyAtRule(range, result); |
| 166 } else { | 189 } else { |
| 167 result.append(range.consume()); | 190 result.append(range.consume()); |
| 168 } | 191 } |
| 169 } | 192 } |
| 170 return success; | 193 return success; |
| 171 } | 194 } |
| 172 | 195 |
| 173 const CSSValue* CSSVariableResolver::resolveVariableReferences( | 196 const CSSValue* CSSVariableResolver::resolveVariableReferences( |
| 174 const StyleResolverState& state, | 197 const StyleResolverState& state, |
| 175 CSSPropertyID id, | 198 CSSPropertyID id, |
| 176 const CSSValue& value) { | 199 const CSSValue& value, |
| 200 bool disallowAnimationTainted) { |
| 177 ASSERT(!isShorthandProperty(id)); | 201 ASSERT(!isShorthandProperty(id)); |
| 178 | 202 |
| 179 if (value.isPendingSubstitutionValue()) | 203 if (value.isPendingSubstitutionValue()) { |
| 180 return resolvePendingSubstitutions(state, id, | 204 return resolvePendingSubstitutions(state, id, |
| 181 toCSSPendingSubstitutionValue(value)); | 205 toCSSPendingSubstitutionValue(value), |
| 206 disallowAnimationTainted); |
| 207 } |
| 182 | 208 |
| 183 if (value.isVariableReferenceValue()) | 209 if (value.isVariableReferenceValue()) { |
| 184 return resolveVariableReferences(state, id, | 210 return resolveVariableReferences(state, id, |
| 185 toCSSVariableReferenceValue(value)); | 211 toCSSVariableReferenceValue(value), |
| 212 disallowAnimationTainted); |
| 213 } |
| 186 | 214 |
| 187 NOTREACHED(); | 215 NOTREACHED(); |
| 188 return nullptr; | 216 return nullptr; |
| 189 } | 217 } |
| 190 | 218 |
| 191 const CSSValue* CSSVariableResolver::resolveVariableReferences( | 219 const CSSValue* CSSVariableResolver::resolveVariableReferences( |
| 192 const StyleResolverState& state, | 220 const StyleResolverState& state, |
| 193 CSSPropertyID id, | 221 CSSPropertyID id, |
| 194 const CSSVariableReferenceValue& value) { | 222 const CSSVariableReferenceValue& value, |
| 223 bool disallowAnimationTainted) { |
| 195 CSSVariableResolver resolver(state); | 224 CSSVariableResolver resolver(state); |
| 196 Vector<CSSParserToken> tokens; | 225 Vector<CSSParserToken> tokens; |
| 197 if (!resolver.resolveTokenRange(value.variableDataValue()->tokens(), tokens)) | 226 bool isAnimationTainted = false; |
| 227 if (!resolver.resolveTokenRange(value.variableDataValue()->tokens(), |
| 228 disallowAnimationTainted, tokens, |
| 229 isAnimationTainted)) |
| 198 return CSSUnsetValue::create(); | 230 return CSSUnsetValue::create(); |
| 199 const CSSValue* result = | 231 const CSSValue* result = |
| 200 CSSPropertyParser::parseSingleValue(id, tokens, strictCSSParserContext()); | 232 CSSPropertyParser::parseSingleValue(id, tokens, strictCSSParserContext()); |
| 201 if (!result) | 233 if (!result) |
| 202 return CSSUnsetValue::create(); | 234 return CSSUnsetValue::create(); |
| 203 return result; | 235 return result; |
| 204 } | 236 } |
| 205 | 237 |
| 206 const CSSValue* CSSVariableResolver::resolvePendingSubstitutions( | 238 const CSSValue* CSSVariableResolver::resolvePendingSubstitutions( |
| 207 const StyleResolverState& state, | 239 const StyleResolverState& state, |
| 208 CSSPropertyID id, | 240 CSSPropertyID id, |
| 209 const CSSPendingSubstitutionValue& pendingValue) { | 241 const CSSPendingSubstitutionValue& pendingValue, |
| 242 bool disallowAnimationTainted) { |
| 210 // Longhands from shorthand references follow this path. | 243 // Longhands from shorthand references follow this path. |
| 211 HeapHashMap<CSSPropertyID, Member<const CSSValue>>& propertyCache = | 244 HeapHashMap<CSSPropertyID, Member<const CSSValue>>& propertyCache = |
| 212 state.parsedPropertiesForPendingSubstitutionCache(pendingValue); | 245 state.parsedPropertiesForPendingSubstitutionCache(pendingValue); |
| 213 | 246 |
| 214 const CSSValue* value = propertyCache.get(id); | 247 const CSSValue* value = propertyCache.get(id); |
| 215 if (!value) { | 248 if (!value) { |
| 216 // TODO(timloh): We shouldn't retry this for all longhands if the shorthand | 249 // TODO(timloh): We shouldn't retry this for all longhands if the shorthand |
| 217 // ends up invalid. | 250 // ends up invalid. |
| 218 CSSVariableReferenceValue* shorthandValue = pendingValue.shorthandValue(); | 251 CSSVariableReferenceValue* shorthandValue = pendingValue.shorthandValue(); |
| 219 CSSPropertyID shorthandPropertyId = pendingValue.shorthandPropertyId(); | 252 CSSPropertyID shorthandPropertyId = pendingValue.shorthandPropertyId(); |
| 220 | 253 |
| 221 CSSVariableResolver resolver(state); | 254 CSSVariableResolver resolver(state); |
| 222 | 255 |
| 223 Vector<CSSParserToken> tokens; | 256 Vector<CSSParserToken> tokens; |
| 257 bool isAnimationTainted = false; |
| 224 if (resolver.resolveTokenRange( | 258 if (resolver.resolveTokenRange( |
| 225 shorthandValue->variableDataValue()->tokens(), tokens)) { | 259 shorthandValue->variableDataValue()->tokens(), |
| 260 disallowAnimationTainted, tokens, isAnimationTainted)) { |
| 226 CSSParserContext context(HTMLStandardMode, 0); | 261 CSSParserContext context(HTMLStandardMode, 0); |
| 227 | 262 |
| 228 HeapVector<CSSProperty, 256> parsedProperties; | 263 HeapVector<CSSProperty, 256> parsedProperties; |
| 229 | 264 |
| 230 if (CSSPropertyParser::parseValue( | 265 if (CSSPropertyParser::parseValue( |
| 231 shorthandPropertyId, false, CSSParserTokenRange(tokens), context, | 266 shorthandPropertyId, false, CSSParserTokenRange(tokens), context, |
| 232 parsedProperties, StyleRule::RuleType::Style)) { | 267 parsedProperties, StyleRule::RuleType::Style)) { |
| 233 unsigned parsedPropertiesCount = parsedProperties.size(); | 268 unsigned parsedPropertiesCount = parsedProperties.size(); |
| 234 for (unsigned i = 0; i < parsedPropertiesCount; ++i) { | 269 for (unsigned i = 0; i < parsedPropertiesCount; ++i) { |
| 235 propertyCache.set(parsedProperties[i].id(), | 270 propertyCache.set(parsedProperties[i].id(), |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 : m_styleResolverState(state), | 305 : m_styleResolverState(state), |
| 271 m_inheritedVariables(state.style()->inheritedVariables()), | 306 m_inheritedVariables(state.style()->inheritedVariables()), |
| 272 m_nonInheritedVariables(state.style()->nonInheritedVariables()), | 307 m_nonInheritedVariables(state.style()->nonInheritedVariables()), |
| 273 m_registry(state.document().propertyRegistry()) {} | 308 m_registry(state.document().propertyRegistry()) {} |
| 274 | 309 |
| 275 DEFINE_TRACE(CSSVariableResolver) { | 310 DEFINE_TRACE(CSSVariableResolver) { |
| 276 visitor->trace(m_registry); | 311 visitor->trace(m_registry); |
| 277 } | 312 } |
| 278 | 313 |
| 279 } // namespace blink | 314 } // namespace blink |
| OLD | NEW |