1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /* bit vectors for sets of CSS properties */
7 #ifndef nsCSSPropertyIDSet_h__
8 #define nsCSSPropertyIDSet_h__
10 #include <initializer_list>
11 #include <limits.h> // for CHAR_BIT
14 #include "mozilla/ArrayUtils.h"
15 // For COMPOSITOR_ANIMATABLE_PROPERTY_LIST and
16 // COMPOSITOR_ANIMATABLE_PROPERTY_LIST_LENGTH
17 #include "mozilla/CompositorAnimatableProperties.h"
18 #include "nsCSSProps.h" // For operator<< for nsCSSPropertyID
19 #include "nsCSSPropertyID.h"
22 * nsCSSPropertyIDSet maintains a set of non-shorthand CSS properties. In
23 * other words, for each longhand CSS property we support, it has a bit
24 * for whether that property is in the set.
26 class nsCSSPropertyIDSet
{
28 nsCSSPropertyIDSet() { Empty(); }
29 // auto-generated copy-constructor OK
31 explicit constexpr nsCSSPropertyIDSet(
32 std::initializer_list
<nsCSSPropertyID
> aProperties
)
34 for (auto property
: aProperties
) {
36 mProperties
[p
/ kBitsInChunk
] |= property_set_type(1)
37 << (p
% kBitsInChunk
);
41 void AssertInSetRange(nsCSSPropertyID aProperty
) const {
42 NS_ASSERTION(0 <= aProperty
&& aProperty
< eCSSProperty_COUNT_no_shorthands
,
46 // Conversion of aProperty to |size_t| after AssertInSetRange
47 // lets the compiler generate significantly tighter code.
49 void AddProperty(nsCSSPropertyID aProperty
) {
50 AssertInSetRange(aProperty
);
52 mProperties
[p
/ kBitsInChunk
] |= property_set_type(1) << (p
% kBitsInChunk
);
55 void RemoveProperty(nsCSSPropertyID aProperty
) {
56 AssertInSetRange(aProperty
);
58 mProperties
[p
/ kBitsInChunk
] &=
59 ~(property_set_type(1) << (p
% kBitsInChunk
));
62 bool HasProperty(nsCSSPropertyID aProperty
) const {
63 AssertInSetRange(aProperty
);
65 return (mProperties
[p
/ kBitsInChunk
] &
66 (property_set_type(1) << (p
% kBitsInChunk
))) != 0;
69 // Returns an nsCSSPropertyIDSet including all properties that can be run
71 static constexpr nsCSSPropertyIDSet
CompositorAnimatables() {
72 return nsCSSPropertyIDSet(COMPOSITOR_ANIMATABLE_PROPERTY_LIST
);
75 static constexpr size_t CompositorAnimatableCount() {
76 return COMPOSITOR_ANIMATABLE_PROPERTY_LIST_LENGTH
;
79 static constexpr size_t CompositorAnimatableDisplayItemCount() {
80 // We have 3 individual transforms and 4 motion path properties, and they
81 // also use DisplayItemType::TYPE_TRANSFORM.
82 return COMPOSITOR_ANIMATABLE_PROPERTY_LIST_LENGTH
- 7;
85 static constexpr nsCSSPropertyIDSet
CSSTransformProperties() {
86 return nsCSSPropertyIDSet
{eCSSProperty_transform
, eCSSProperty_translate
,
87 eCSSProperty_rotate
, eCSSProperty_scale
};
90 static constexpr nsCSSPropertyIDSet
MotionPathProperties() {
91 // FIXME: Bug 1559232: Add offset-position.
92 return nsCSSPropertyIDSet
{
93 eCSSProperty_offset_path
, eCSSProperty_offset_distance
,
94 eCSSProperty_offset_rotate
, eCSSProperty_offset_anchor
};
97 static constexpr nsCSSPropertyIDSet
TransformLikeProperties() {
98 // FIXME: Bug 1559232: Add offset-position.
99 return nsCSSPropertyIDSet
{
100 eCSSProperty_transform
, eCSSProperty_translate
,
101 eCSSProperty_rotate
, eCSSProperty_scale
,
102 eCSSProperty_offset_path
, eCSSProperty_offset_distance
,
103 eCSSProperty_offset_rotate
, eCSSProperty_offset_anchor
};
106 static constexpr nsCSSPropertyIDSet
OpacityProperties() {
107 return nsCSSPropertyIDSet
{eCSSProperty_opacity
};
110 bool Intersects(const nsCSSPropertyIDSet
& aOther
) const {
111 for (size_t i
= 0; i
< mozilla::ArrayLength(mProperties
); ++i
) {
112 if (mProperties
[i
] & aOther
.mProperties
[i
]) {
119 void Empty() { memset(mProperties
, 0, sizeof(mProperties
)); }
121 void AssertIsEmpty(const char* aText
) const {
122 for (size_t i
= 0; i
< mozilla::ArrayLength(mProperties
); ++i
) {
123 NS_ASSERTION(mProperties
[i
] == 0, aText
);
127 bool Equals(const nsCSSPropertyIDSet
& aOther
) const {
128 return mozilla::ArrayEqual(mProperties
, aOther
.mProperties
);
131 bool IsEmpty() const {
132 for (size_t i
= 0; i
< mozilla::ArrayLength(mProperties
); ++i
) {
133 if (mProperties
[i
] != 0) {
140 bool IsSubsetOf(const nsCSSPropertyIDSet
& aOther
) const {
141 return this->Intersect(aOther
).Equals(*this);
144 // Return a new nsCSSPropertyIDSet which is the inverse of this set.
145 nsCSSPropertyIDSet
Inverse() const {
146 nsCSSPropertyIDSet result
;
147 for (size_t i
= 0; i
< mozilla::ArrayLength(mProperties
); ++i
) {
148 result
.mProperties
[i
] = ~mProperties
[i
];
153 // Returns a new nsCSSPropertyIDSet with all properties that are both in
154 // this set and |aOther|.
155 nsCSSPropertyIDSet
Intersect(const nsCSSPropertyIDSet
& aOther
) const {
156 nsCSSPropertyIDSet result
;
157 for (size_t i
= 0; i
< mozilla::ArrayLength(mProperties
); ++i
) {
158 result
.mProperties
[i
] = mProperties
[i
] & aOther
.mProperties
[i
];
163 // Return a new nsCSSPropertyIDSet with all properties that are in either
164 // this set or |aOther| but not both.
165 nsCSSPropertyIDSet
Xor(const nsCSSPropertyIDSet
& aOther
) const {
166 nsCSSPropertyIDSet result
;
167 for (size_t i
= 0; i
< mozilla::ArrayLength(mProperties
); ++i
) {
168 result
.mProperties
[i
] = mProperties
[i
] ^ aOther
.mProperties
[i
];
173 nsCSSPropertyIDSet
& operator|=(const nsCSSPropertyIDSet
& aOther
) {
174 for (size_t i
= 0; i
< mozilla::ArrayLength(mProperties
); ++i
) {
175 mProperties
[i
] |= aOther
.mProperties
[i
];
181 typedef unsigned long property_set_type
;
184 // number of bits in |property_set_type|.
185 static const size_t kBitsInChunk
= sizeof(property_set_type
) * CHAR_BIT
;
186 // number of |property_set_type|s in the set
187 static const size_t kChunkCount
=
188 (eCSSProperty_COUNT_no_shorthands
+ kBitsInChunk
- 1) / kBitsInChunk
;
191 * For fast enumeration of all the bits that are set, callers can
192 * check each chunk against zero (since in normal cases few bits are
195 bool HasPropertyInChunk(size_t aChunk
) const {
196 return mProperties
[aChunk
] != 0;
198 bool HasPropertyAt(size_t aChunk
, size_t aBit
) const {
199 return (mProperties
[aChunk
] & (property_set_type(1) << aBit
)) != 0;
201 static nsCSSPropertyID
CSSPropertyAt(size_t aChunk
, size_t aBit
) {
202 return nsCSSPropertyID(aChunk
* kBitsInChunk
+ aBit
);
205 // Iterator for use in range-based for loops
208 Iterator(Iterator
&& aOther
)
209 : mPropertySet(aOther
.mPropertySet
),
210 mChunk(aOther
.mChunk
),
213 static Iterator
BeginIterator(const nsCSSPropertyIDSet
& aPropertySet
) {
214 Iterator
result(aPropertySet
);
216 // Search for the first property.
217 // Unsigned integer overflow is defined so the following is safe.
224 static Iterator
EndIterator(const nsCSSPropertyIDSet
& aPropertySet
) {
225 Iterator
result(aPropertySet
);
226 result
.mChunk
= kChunkCount
;
231 bool operator!=(const Iterator
& aOther
) const {
232 return mChunk
!= aOther
.mChunk
|| mBit
!= aOther
.mBit
;
235 Iterator
& operator++() {
236 MOZ_ASSERT(mChunk
< kChunkCount
, "Should not iterate beyond end");
240 } while (mBit
< kBitsInChunk
&&
241 !mPropertySet
.HasPropertyAt(mChunk
, mBit
));
242 if (mBit
!= kBitsInChunk
) {
248 } while (mChunk
< kChunkCount
&&
249 !mPropertySet
.HasPropertyInChunk(mChunk
));
251 if (mChunk
!= kChunkCount
) {
252 while (mBit
< kBitsInChunk
&&
253 !mPropertySet
.HasPropertyAt(mChunk
, mBit
)) {
261 nsCSSPropertyID
operator*() {
262 MOZ_ASSERT(mChunk
< kChunkCount
, "Should not dereference beyond end");
263 return nsCSSPropertyIDSet::CSSPropertyAt(mChunk
, mBit
);
267 explicit Iterator(const nsCSSPropertyIDSet
& aPropertySet
)
268 : mPropertySet(aPropertySet
) {}
271 Iterator(const Iterator
&) = delete;
272 Iterator
& operator=(const Iterator
&) = delete;
273 Iterator
& operator=(const Iterator
&&) = delete;
275 const nsCSSPropertyIDSet
& mPropertySet
;
280 Iterator
begin() const { return Iterator::BeginIterator(*this); }
281 Iterator
end() const { return Iterator::EndIterator(*this); }
284 property_set_type mProperties
[kChunkCount
];
289 inline std::ostream
& operator<<(std::ostream
& aOut
,
290 const nsCSSPropertyIDSet
& aPropertySet
) {
291 AutoTArray
<nsCSSPropertyID
, 16> properties
;
292 for (nsCSSPropertyID property
: aPropertySet
) {
293 properties
.AppendElement(property
);
295 return aOut
<< properties
;
298 #endif /* !defined(nsCSSPropertyIDSet_h__) */