1 // Copyright 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CASCADE_RESOLVER_H_ 6 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CASCADE_RESOLVER_H_ 7 8 #include "base/auto_reset.h" 9 #include "third_party/blink/renderer/core/core_export.h" 10 #include "third_party/blink/renderer/core/css/css_property_name.h" 11 #include "third_party/blink/renderer/core/css/properties/css_property.h" 12 #include "third_party/blink/renderer/core/css/resolver/cascade_filter.h" 13 #include "third_party/blink/renderer/core/css/resolver/cascade_origin.h" 14 #include "third_party/blink/renderer/core/css/rule_set.h" 15 16 namespace blink { 17 18 class CascadePriority; 19 class CSSProperty; 20 class CSSVariableData; 21 class CSSProperty; 22 23 namespace cssvalue { 24 25 class CSSPendingSubstitutionValue; 26 27 } // namespace cssvalue 28 29 // CascadeResolver is an object passed on the stack during Apply. Its most 30 // important job is to detect cycles during Apply (in general, keep track of 31 // which properties we're currently applying). 32 class CORE_EXPORT CascadeResolver { 33 STACK_ALLOCATED(); 34 35 public: 36 // TODO(crbug.com/985047): Probably use a HashMap for this. 37 using PropertyStack = Vector<const CSSProperty*, 8>; 38 39 // A 'locked' property is a property we are in the process of applying. 40 // In other words, once a property is locked, locking it again would form 41 // a cycle, and is therefore an error. 42 bool IsLocked(const CSSProperty&) const; 43 44 // Returns the property we're currently applying. CurrentProperty()45 const CSSProperty* CurrentProperty() const { 46 return stack_.size() ? stack_.back() : nullptr; 47 } 48 49 // We do not allow substitution of animation-tainted values into 50 // an animation-affecting property. 51 // 52 // https://drafts.csswg.org/css-variables/#animation-tainted 53 bool AllowSubstitution(CSSVariableData*) const; 54 55 // Sets the generation of the priority to zero, which has the effect of 56 // marking it as unapplied. (I.e. this can be used to force re-application of 57 // a declaration). 58 void MarkUnapplied(CascadePriority*) const; 59 60 // Sets the generation of the priority to the current generation, 61 // which has the effect of marking it as already applied. (I.e. this can be 62 // used to skip application of a declaration). 63 void MarkApplied(CascadePriority*) const; 64 65 // If the incoming origin is kAuthor, collect flags from 'property'. 66 // AuthorFlags() can then later be used to see which flags have been observed. CollectAuthorFlags(const CSSProperty & property,CascadeOrigin origin)67 void CollectAuthorFlags(const CSSProperty& property, CascadeOrigin origin) { 68 author_flags_ |= 69 (origin == CascadeOrigin::kAuthor ? property.GetFlags() : 0); 70 } AuthorFlags()71 CSSProperty::Flags AuthorFlags() const { return author_flags_; } 72 73 // Automatically locks and unlocks the given property. (See 74 // CascadeResolver::IsLocked). 75 class CORE_EXPORT AutoLock { 76 STACK_ALLOCATED(); 77 78 public: 79 AutoLock(const CSSProperty&, CascadeResolver&); 80 ~AutoLock(); 81 82 private: 83 CascadeResolver& resolver_; 84 }; 85 86 private: 87 friend class AutoLock; 88 friend class StyleCascade; 89 friend class TestCascadeResolver; 90 CascadeResolver(CascadeFilter filter,uint8_t generation)91 CascadeResolver(CascadeFilter filter, uint8_t generation) 92 : filter_(filter), generation_(generation) {} 93 94 // If the given property is already being applied, returns true. 95 // The return value is the same value you would get from InCycle(), and 96 // is just returned for convenience. 97 // 98 // When a cycle has been detected, the CascadeResolver will *persist the cycle 99 // state* (i.e. InCycle() will continue to return true) until we reach 100 // the start of the cycle. 101 // 102 // The cycle state is cleared by ~AutoLock, once we have moved far enough 103 // up the stack. 104 bool DetectCycle(const CSSProperty&); 105 // Returns true whenever the CascadeResolver is in a cycle state. 106 // This DOES NOT detect cycles; the caller must call DetectCycle first. 107 bool InCycle() const; 108 // Returns the index of the given property (compared using the property's 109 // CSSPropertyName), or kNotFound if the property (name) is not present in 110 // stack_. 111 wtf_size_t Find(const CSSProperty&) const; 112 113 PropertyStack stack_; 114 wtf_size_t cycle_depth_ = kNotFound; 115 CascadeFilter filter_; 116 const uint8_t generation_ = 0; 117 CSSProperty::Flags author_flags_ = 0; 118 119 // A very simple cache for CSSPendingSubstitutionValues. We cache only the 120 // most recently parsed CSSPendingSubstitutionValue, such that consecutive 121 // calls to ResolvePendingSubstitution with the same value don't need to 122 // do the same parsing job all over again. 123 struct { 124 STACK_ALLOCATED(); 125 126 public: 127 const cssvalue::CSSPendingSubstitutionValue* value = nullptr; 128 HeapVector<CSSPropertyValue, 256> parsed_properties; 129 } shorthand_cache_; 130 }; 131 132 } // namespace blink 133 134 #endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CASCADE_RESOLVER_H_ 135