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