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_PRIORITY_H_
6 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CASCADE_PRIORITY_H_
7 
8 #include "base/check_op.h"
9 #include "third_party/blink/renderer/core/core_export.h"
10 #include "third_party/blink/renderer/core/css/resolver/cascade_origin.h"
11 
12 namespace blink {
13 
14 // The origin and importance criteria are evaluated together [1], hence we
15 // encode both into a single integer which will do the right thing when compared
16 // to another such encoded integer. See CascadeOrigin for more information on
17 // how that works.
18 //
19 // [1] https://www.w3.org/TR/css-cascade-3/#cascade-origin
EncodeOriginImportance(CascadeOrigin origin,bool important)20 inline uint64_t EncodeOriginImportance(CascadeOrigin origin, bool important) {
21   uint8_t important_xor = (static_cast<uint8_t>(!important) - 1) & 0xF;
22   return static_cast<uint64_t>(origin) ^ important_xor;
23 }
24 
25 // Tree order bits are flipped for important declarations to reverse the
26 // priority [1].
27 //
28 // [1] https://drafts.csswg.org/css-scoping/#shadow-cascading
EncodeTreeOrder(uint16_t tree_order,bool important)29 inline uint64_t EncodeTreeOrder(uint16_t tree_order, bool important) {
30   uint16_t important_xor = static_cast<uint16_t>(!important) - 1;
31   return static_cast<uint64_t>(tree_order) ^ important_xor;
32 }
33 
34 // The CascadePriority class encapsulates a subset of the cascading criteria
35 // described by css-cascade [1], and provides a way to compare priorities
36 // quickly by encoding all the information in a single integer.
37 //
38 // It encompasses, from most significant to least significant:
39 // Origin/importance; tree order, which is a number representing the
40 // shadow-including tree order [2]; position, which contains the index (or
41 // indices) required to lookup a declaration in the underlying structure (e.g. a
42 // MatchResult); and finally generation, which is a monotonically increasing
43 // number generated by StyleCascade for each call to StyleCascade::Apply.
44 //
45 // [1] https://drafts.csswg.org/css-cascade/#cascading
46 // [2] https://drafts.csswg.org/css-scoping/#shadow-cascading
47 class CORE_EXPORT CascadePriority {
48  public:
49   // The declaration is important if this bit is set on the encoded priority.
50   static constexpr uint64_t kImportantBit = 55;
51   static constexpr uint64_t kOriginImportanceOffset = 52;
52   static constexpr uint64_t kTreeOrderOffset = 36;
53 
CascadePriority()54   CascadePriority() : bits_(0) {}
CascadePriority(CascadeOrigin origin)55   CascadePriority(CascadeOrigin origin)
56       : CascadePriority(origin, false, 0, 0) {}
CascadePriority(CascadeOrigin origin,bool important)57   CascadePriority(CascadeOrigin origin, bool important)
58       : CascadePriority(origin, important, 0, 0) {}
CascadePriority(CascadeOrigin origin,bool important,uint16_t tree_order)59   CascadePriority(CascadeOrigin origin, bool important, uint16_t tree_order)
60       : CascadePriority(origin, important, tree_order, 0) {}
61   // For an explanation of 'tree_order', see css-scoping:
62   // https://drafts.csswg.org/css-scoping/#shadow-cascading
CascadePriority(CascadeOrigin origin,bool important,uint16_t tree_order,uint32_t position)63   CascadePriority(CascadeOrigin origin,
64                   bool important,
65                   uint16_t tree_order,
66                   uint32_t position)
67       : bits_(static_cast<uint64_t>(position) << 4 |
68               EncodeTreeOrder(tree_order, important) << kTreeOrderOffset |
69               EncodeOriginImportance(origin, important)
70                   << kOriginImportanceOffset) {}
71   // See StyleCascade.generation_.
CascadePriority(CascadePriority o,uint8_t generation)72   CascadePriority(CascadePriority o, uint8_t generation)
73       : bits_((o.bits_ & ~static_cast<uint8_t>(0xF)) | generation) {
74     DCHECK_LE(generation, 0xF);
75   }
76 
IsImportant()77   bool IsImportant() const { return (bits_ >> kImportantBit) & 1; }
GetOrigin()78   CascadeOrigin GetOrigin() const {
79     uint64_t important_xor = (((~bits_ >> kImportantBit) & 1) - 1) & 0xF;
80     return static_cast<CascadeOrigin>((bits_ >> kOriginImportanceOffset) ^
81                                       important_xor);
82   }
HasOrigin()83   bool HasOrigin() const { return GetOrigin() != CascadeOrigin::kNone; }
GetPosition()84   uint32_t GetPosition() const { return (bits_ >> 4) & 0xFFFFFFFF; }
GetGeneration()85   uint8_t GetGeneration() const { return bits_ & 0xF; }
86 
87   bool operator>=(const CascadePriority& o) const { return bits_ >= o.bits_; }
88   bool operator<(const CascadePriority& o) const { return bits_ < o.bits_; }
89   bool operator==(const CascadePriority& o) const { return bits_ == o.bits_; }
90   bool operator!=(const CascadePriority& o) const { return bits_ != o.bits_; }
91 
92  private:
93   friend class StyleCascade;
94   friend class StyleCascadeTest;
95 
CascadePriority(uint64_t bits)96   CascadePriority(uint64_t bits) : bits_(bits) {}
97 
98   //  Bit  0-3 : generation
99   //  Bit  4-35: position
100   //  Bit 36-51: tree_order (encoded)
101   //  Bit 52-59: origin/importance (encoded)
102   uint64_t bits_;
103 };
104 
105 }  // namespace blink
106 
107 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CASCADE_PRIORITY_H_
108