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