1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * compact representation of the property-value pairs within a CSS
8 * declaration, and the code for expanding and compacting it
11 #ifndef nsCSSDataBlock_h__
12 #define nsCSSDataBlock_h__
14 #include "mozilla/MemoryReporting.h"
15 #include "nsCSSProps.h"
16 #include "nsCSSPropertySet.h"
17 #include "nsCSSValue.h"
18 #include "imgRequestProxy.h"
21 class nsCSSExpandedDataBlock
;
30 * An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of
31 * property-value data for a CSS declaration block (which we misname a
32 * |css::Declaration|). Mutation is accomplished through
33 * |nsCSSExpandedDataBlock| or in some cases via direct slot access.
35 class nsCSSCompressedDataBlock
{
37 friend class nsCSSExpandedDataBlock
;
39 // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock
40 // (in |Compress|) can create compressed data blocks.
41 explicit nsCSSCompressedDataBlock(uint32_t aNumProps
)
42 : mStyleBits(0), mNumProps(aNumProps
)
46 ~nsCSSCompressedDataBlock();
49 * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style
50 * rule using this block for storage.
52 void MapRuleInfoInto(nsRuleData
*aRuleData
) const;
55 * Return the location at which the *value* for the property is
56 * stored, or null if the block does not contain a value for the
59 * Inefficient (by design).
61 * Must not be called for shorthands.
63 const nsCSSValue
* ValueFor(nsCSSProperty aProperty
) const;
66 * Attempt to replace the value for |aProperty| stored in this block
67 * with the matching value stored in |aFromBlock|.
68 * This method will fail (returning false) if |aProperty| is not
69 * already in this block. It will set |aChanged| to true if it
70 * actually made a change to the block, but regardless, if it
71 * returns true, the value in |aFromBlock| was erased.
73 bool TryReplaceValue(nsCSSProperty aProperty
,
74 nsCSSExpandedDataBlock
& aFromBlock
,
78 * Clone this block, or return null on out-of-memory.
80 nsCSSCompressedDataBlock
* Clone() const;
83 * Create a new nsCSSCompressedDataBlock holding no declarations.
85 static nsCSSCompressedDataBlock
* CreateEmptyBlock();
87 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
89 bool HasDefaultBorderImageSlice() const;
90 bool HasDefaultBorderImageWidth() const;
91 bool HasDefaultBorderImageOutset() const;
92 bool HasDefaultBorderImageRepeat() const;
95 void* operator new(size_t aBaseSize
, uint32_t aNumProps
) {
96 NS_ABORT_IF_FALSE(aBaseSize
== sizeof(nsCSSCompressedDataBlock
),
97 "unexpected size for nsCSSCompressedDataBlock");
98 return ::operator new(aBaseSize
+ DataSize(aNumProps
));
102 // Ideally, |nsCSSProperty| would be |enum nsCSSProperty : int16_t|. But
103 // not all of the compilers we use are modern enough to support small
104 // enums. So we manually squeeze nsCSSProperty into 16 bits ourselves.
105 // The static assertion below ensures it fits.
106 typedef int16_t CompressedCSSProperty
;
107 static const size_t MaxCompressedCSSProperty
= INT16_MAX
;
110 static size_t DataSize(uint32_t aNumProps
) {
111 return size_t(aNumProps
) *
112 (sizeof(nsCSSValue
) + sizeof(CompressedCSSProperty
));
115 int32_t mStyleBits
; // the structs for which we have data, according to
116 // |nsCachedStyleData::GetBitForSID|.
118 // nsCSSValue elements are stored after these fields, and
119 // nsCSSProperty elements are stored -- each one compressed as a
120 // CompressedCSSProperty -- after the nsCSSValue elements. Space for them
121 // is allocated in |operator new| above. The static assertions following
122 // this class make sure that the value and property elements are aligned
125 nsCSSValue
* Values() const {
126 return (nsCSSValue
*)(this + 1);
129 CompressedCSSProperty
* CompressedProperties() const {
130 return (CompressedCSSProperty
*)(Values() + mNumProps
);
133 nsCSSValue
* ValueAtIndex(uint32_t i
) const {
134 NS_ABORT_IF_FALSE(i
< mNumProps
, "value index out of range");
138 nsCSSProperty
PropertyAtIndex(uint32_t i
) const {
139 NS_ABORT_IF_FALSE(i
< mNumProps
, "property index out of range");
140 nsCSSProperty prop
= (nsCSSProperty
)CompressedProperties()[i
];
141 NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(prop
), "out of range");
145 void CopyValueToIndex(uint32_t i
, nsCSSValue
* aValue
) {
146 new (ValueAtIndex(i
)) nsCSSValue(*aValue
);
149 void RawCopyValueToIndex(uint32_t i
, nsCSSValue
* aValue
) {
150 memcpy(ValueAtIndex(i
), aValue
, sizeof(nsCSSValue
));
153 void SetPropertyAtIndex(uint32_t i
, nsCSSProperty aProperty
) {
154 NS_ABORT_IF_FALSE(i
< mNumProps
, "set property index out of range");
155 CompressedProperties()[i
] = (CompressedCSSProperty
)aProperty
;
158 void SetNumPropsToZero() {
163 // Make sure the values and properties are aligned appropriately. (These
164 // assertions are stronger than necessary to keep them simple.)
165 static_assert(sizeof(nsCSSCompressedDataBlock
) == 8,
166 "nsCSSCompressedDataBlock's size has changed");
167 static_assert(NS_ALIGNMENT_OF(nsCSSValue
) == 4 || NS_ALIGNMENT_OF(nsCSSValue
) == 8,
168 "nsCSSValue doesn't align with nsCSSCompressedDataBlock");
169 static_assert(NS_ALIGNMENT_OF(nsCSSCompressedDataBlock::CompressedCSSProperty
) == 2,
170 "CompressedCSSProperty doesn't align with nsCSSValue");
172 // Make sure that sizeof(CompressedCSSProperty) is big enough.
173 static_assert(eCSSProperty_COUNT_no_shorthands
<=
174 nsCSSCompressedDataBlock::MaxCompressedCSSProperty
,
175 "nsCSSProperty doesn't fit in StoredSizeOfCSSProperty");
177 class nsCSSExpandedDataBlock
{
178 friend class nsCSSCompressedDataBlock
;
181 nsCSSExpandedDataBlock();
182 ~nsCSSExpandedDataBlock();
185 /* Property storage may not be accessed directly; use AddLonghandProperty
188 nsCSSValue mValues
[eCSSProperty_COUNT_no_shorthands
];
192 * Transfer all of the state from a pair of compressed data blocks
193 * to this expanded block. This expanded block must be clear
196 * This method DELETES both of the compressed data blocks it is
197 * passed. (This is necessary because ownership of sub-objects
198 * is transferred to the expanded block.)
200 void Expand(nsCSSCompressedDataBlock
*aNormalBlock
,
201 nsCSSCompressedDataBlock
*aImportantBlock
);
204 * Allocate new compressed blocks and transfer all of the state
205 * from this expanded block to the new blocks, clearing this
206 * expanded block. A normal block will always be allocated, but
207 * an important block will only be allocated if there are
208 * !important properties in the expanded block; otherwise
209 * |*aImportantBlock| will be set to null.
211 void Compress(nsCSSCompressedDataBlock
**aNormalBlock
,
212 nsCSSCompressedDataBlock
**aImportantBlock
);
215 * Copy a value into this expanded block. This does NOT destroy
216 * the source value object. |aProperty| cannot be a shorthand.
218 void AddLonghandProperty(nsCSSProperty aProperty
, const nsCSSValue
& aValue
);
221 * Clear the state of this expanded block.
226 * Clear the data for the given property (including the set and
227 * important bits). Can be used with shorthand properties.
229 void ClearProperty(nsCSSProperty aPropID
);
232 * Same as ClearProperty, but faster and cannot be used with shorthands.
234 void ClearLonghandProperty(nsCSSProperty aPropID
);
237 * Transfer the state for |aPropID| (which may be a shorthand)
238 * from |aFromBlock| to this block. The property being transferred
239 * is !important if |aIsImportant| is true, and should replace an
240 * existing !important property regardless of its own importance
241 * if |aOverrideImportant| is true.
243 * Returns true if something changed, false otherwise. Calls
244 * |ValueAppended| on |aDeclaration| if the property was not
245 * previously set, or in any case if |aMustCallValueAppended| is true.
247 bool TransferFromBlock(nsCSSExpandedDataBlock
& aFromBlock
,
248 nsCSSProperty aPropID
,
250 bool aOverrideImportant
,
251 bool aMustCallValueAppended
,
252 mozilla::css::Declaration
* aDeclaration
);
255 * Copies the values for aPropID into the specified aRuleData object.
257 * This is used for copying parsed-at-computed-value-time properties
258 * that had variable references. aPropID must be a longhand property.
260 void MapRuleInfoInto(nsCSSProperty aPropID
, nsRuleData
* aRuleData
) const;
262 void AssertInitialState() {
264 DoAssertInitialState();
270 * Compute the number of properties that will be present in the
271 * result of |Compress|.
273 void ComputeNumProps(uint32_t* aNumPropsNormal
,
274 uint32_t* aNumPropsImportant
);
276 void DoExpand(nsCSSCompressedDataBlock
*aBlock
, bool aImportant
);
279 * Worker for TransferFromBlock; cannot be used with shorthands.
281 bool DoTransferFromBlock(nsCSSExpandedDataBlock
& aFromBlock
,
282 nsCSSProperty aPropID
,
284 bool aOverrideImportant
,
285 bool aMustCallValueAppended
,
286 mozilla::css::Declaration
* aDeclaration
);
289 void DoAssertInitialState();
293 * mPropertiesSet stores a bit for every property that is present,
294 * to optimize compression of blocks with small numbers of
295 * properties (the norm) and to allow quickly checking whether a
296 * property is set in this block.
298 nsCSSPropertySet mPropertiesSet
;
300 * mPropertiesImportant indicates which properties are '!important'.
302 nsCSSPropertySet mPropertiesImportant
;
305 * Return the storage location within |this| of the value of the
306 * property |aProperty|.
308 nsCSSValue
* PropertyAt(nsCSSProperty aProperty
) {
309 NS_ABORT_IF_FALSE(0 <= aProperty
&&
310 aProperty
< eCSSProperty_COUNT_no_shorthands
,
311 "property out of range");
312 return &mValues
[aProperty
];
314 const nsCSSValue
* PropertyAt(nsCSSProperty aProperty
) const {
315 NS_ABORT_IF_FALSE(0 <= aProperty
&&
316 aProperty
< eCSSProperty_COUNT_no_shorthands
,
317 "property out of range");
318 return &mValues
[aProperty
];
321 void SetPropertyBit(nsCSSProperty aProperty
) {
322 mPropertiesSet
.AddProperty(aProperty
);
325 void ClearPropertyBit(nsCSSProperty aProperty
) {
326 mPropertiesSet
.RemoveProperty(aProperty
);
329 bool HasPropertyBit(nsCSSProperty aProperty
) {
330 return mPropertiesSet
.HasProperty(aProperty
);
333 void SetImportantBit(nsCSSProperty aProperty
) {
334 mPropertiesImportant
.AddProperty(aProperty
);
337 void ClearImportantBit(nsCSSProperty aProperty
) {
338 mPropertiesImportant
.RemoveProperty(aProperty
);
341 bool HasImportantBit(nsCSSProperty aProperty
) {
342 return mPropertiesImportant
.HasProperty(aProperty
);
346 mPropertiesSet
.Empty();
347 mPropertiesImportant
.Empty();
351 #endif /* !defined(nsCSSDataBlock_h__) */