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_FILTER_H_
6 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CASCADE_FILTER_H_
7 
8 #include "third_party/blink/renderer/core/core_export.h"
9 #include "third_party/blink/renderer/core/css/properties/css_property.h"
10 
11 namespace blink {
12 
13 // Reject properties with the given flags set or unset.
14 //
15 // For example, the following applies only inherited properties that don't apply
16 // to ::first-letter:
17 //
18 //  CascadeFilter filter;
19 //  filter = filter.Add(CSSProperty::kInherited, false);
20 //  filter = filter.Add(CSSProperty::kValidForFirstLetter, true);
21 //  filter.Reject(GetCSSPropertyColor());     // -> false
22 //  filter.Reject(GetCSSPropertyDirection()); // -> true
23 //  filter.Reject(GetCSSPropertyTop());       // -> true
24 //
25 class CORE_EXPORT CascadeFilter {
26  public:
27   // Empty filter. Rejects nothing.
28   CascadeFilter() = default;
29 
30   // Creates a filter with a single rule.
31   //
32   // This is equivalent to:
33   //
34   //  CascadeFilter filter;
35   //  filter.Add(flag, v);
36   //
CascadeFilter(CSSProperty::Flag flag,bool v)37   CascadeFilter(CSSProperty::Flag flag, bool v)
38       : mask_(flag), flags_(v ? flag : 0) {}
39 
40   bool operator==(const CascadeFilter& o) const {
41     return mask_ == o.mask_ && flags_ == o.flags_;
42   }
43   bool operator!=(const CascadeFilter& o) const {
44     return mask_ != o.mask_ || flags_ != o.flags_;
45   }
46 
47   // Add a given rule to the filter.
48   //
49   // A flag can be rejected when it's either set or unset. For example
50   //
51   //  CascadeFilter f1(CSSProperty::kInherited, true); // Rejects inherited
52   //  CascadeFilter f2(CSSProperty::kInherited, false); // Rejects non-inherited
53   //
54   // Note that it's not possible to reject both set and unset flags in the same
55   // filter. However, if you wish to reject all properties, you can do so by
56   // using the CSSProperty::kProperty flag.
57   //
58   // Add() will have no effect if there already is a rule for the given flag:
59   //
60   //  CascadeFilter filter;
61   //  CascadeFilter f1 = filter.Add(CSSProperty::kInherited, true);
62   //  CascadeFilter f2 = f1.Add(CSSProperty::kInherited, false);
63   //  bool equal = f1 == f2; // true. Second call to Add had to effect.
64   //
65   // If you want to overwrite a previous rule, use Set().
Add(CSSProperty::Flag flag,bool v)66   CascadeFilter Add(CSSProperty::Flag flag, bool v) const {
67     const CSSProperty::Flags mask = mask_ | flag;
68     const CSSProperty::Flags flags =
69         v ? (flags_ | (flag & ~mask_)) : (flags_ & ~(flag & ~mask_));
70     return CascadeFilter(mask, flags);
71   }
72 
73   // Like Add, except overwrites a previous rule for the same flag.
Set(CSSProperty::Flag flag,bool v)74   CascadeFilter Set(CSSProperty::Flag flag, bool v) const {
75     const CSSProperty::Flags mask = mask_ | flag;
76     const CSSProperty::Flags flags = v ? (flags_ | flag) : (flags_ & ~flag);
77     return CascadeFilter(mask, flags);
78   }
79 
Rejects(const CSSProperty & property)80   bool Rejects(const CSSProperty& property) const {
81     return ~(property.GetFlags() ^ flags_) & mask_;
82   }
83 
Rejects(CSSProperty::Flag flag,bool v)84   bool Rejects(CSSProperty::Flag flag, bool v) const {
85     return ~((v ? flag : 0) ^ flags_) & (mask_ & flag);
86   }
87 
88  private:
CascadeFilter(CSSProperty::Flags mask,CSSProperty::Flags flags)89   CascadeFilter(CSSProperty::Flags mask, CSSProperty::Flags flags)
90       : mask_(mask), flags_(flags) {}
91   // Specifies which bits are significant in flags_. In other words, mask_
92   // contains a '1' at the corresponding position for each flag seen by
93   // Add().
94   CSSProperty::Flags mask_ = 0;
95   // Contains the flags to exclude. Only bits set in mask_ matter.
96   CSSProperty::Flags flags_ = 0;
97 };
98 
99 }  // namespace blink
100 
101 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CASCADE_FILTER_H_
102