123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- /*
- * compact representation of the property-value pairs within a CSS
- * declaration, and the code for expanding and compacting it
- */
- #ifndef nsCSSDataBlock_h__
- #define nsCSSDataBlock_h__
- #include "mozilla/MemoryReporting.h"
- #include "nsCSSProps.h"
- #include "nsCSSPropertyIDSet.h"
- #include "nsCSSValue.h"
- #include "nsStyleStruct.h"
- #include "imgRequestProxy.h"
- struct nsRuleData;
- class nsCSSExpandedDataBlock;
- class nsIDocument;
- namespace mozilla {
- namespace css {
- class Declaration;
- } // namespace css
- } // namespace mozilla
- /**
- * An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of
- * property-value data for a CSS declaration block (which we misname a
- * |css::Declaration|). Mutation is accomplished through
- * |nsCSSExpandedDataBlock| or in some cases via direct slot access.
- */
- class nsCSSCompressedDataBlock
- {
- private:
- friend class nsCSSExpandedDataBlock;
- // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock
- // (in |Compress|) can create compressed data blocks.
- explicit nsCSSCompressedDataBlock(uint32_t aNumProps)
- : mStyleBits(0), mNumProps(aNumProps)
- {}
- public:
- ~nsCSSCompressedDataBlock();
- /**
- * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style
- * rule using this block for storage.
- */
- void MapRuleInfoInto(nsRuleData *aRuleData) const;
- /**
- * Return the location at which the *value* for the property is
- * stored, or null if the block does not contain a value for the
- * property.
- *
- * Inefficient (by design).
- *
- * Must not be called for shorthands.
- */
- const nsCSSValue* ValueFor(nsCSSPropertyID aProperty) const;
- /**
- * Attempt to replace the value for |aProperty| stored in this block
- * with the matching value stored in |aFromBlock|.
- * This method will fail (returning false) if |aProperty| is not
- * already in this block. It will set |aChanged| to true if it
- * actually made a change to the block, but regardless, if it
- * returns true, the value in |aFromBlock| was erased.
- */
- bool TryReplaceValue(nsCSSPropertyID aProperty,
- nsCSSExpandedDataBlock& aFromBlock,
- bool* aChanged);
- /**
- * Clone this block, or return null on out-of-memory.
- */
- nsCSSCompressedDataBlock* Clone() const;
- /**
- * Create a new nsCSSCompressedDataBlock holding no declarations.
- */
- static nsCSSCompressedDataBlock* CreateEmptyBlock();
- size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
- bool HasDefaultBorderImageSlice() const;
- bool HasDefaultBorderImageWidth() const;
- bool HasDefaultBorderImageOutset() const;
- bool HasDefaultBorderImageRepeat() const;
- bool HasInheritedStyleData() const
- {
- return mStyleBits & NS_STYLE_INHERITED_STRUCT_MASK;
- }
- private:
- void* operator new(size_t aBaseSize, uint32_t aNumProps) {
- MOZ_ASSERT(aBaseSize == sizeof(nsCSSCompressedDataBlock),
- "unexpected size for nsCSSCompressedDataBlock");
- return ::operator new(aBaseSize + DataSize(aNumProps));
- }
- public:
- // Ideally, |nsCSSPropertyID| would be |enum nsCSSPropertyID : int16_t|. But
- // not all of the compilers we use are modern enough to support small
- // enums. So we manually squeeze nsCSSPropertyID into 16 bits ourselves.
- // The static assertion below ensures it fits.
- typedef int16_t CompressedCSSProperty;
- static const size_t MaxCompressedCSSProperty = INT16_MAX;
- private:
- static size_t DataSize(uint32_t aNumProps) {
- return size_t(aNumProps) *
- (sizeof(nsCSSValue) + sizeof(CompressedCSSProperty));
- }
- int32_t mStyleBits; // the structs for which we have data, according to
- // |nsCachedStyleData::GetBitForSID|.
- uint32_t mNumProps;
- // nsCSSValue elements are stored after these fields, and
- // nsCSSPropertyID elements are stored -- each one compressed as a
- // CompressedCSSProperty -- after the nsCSSValue elements. Space for them
- // is allocated in |operator new| above. The static assertions following
- // this class make sure that the value and property elements are aligned
- // appropriately.
- nsCSSValue* Values() const {
- return (nsCSSValue*)(this + 1);
- }
- CompressedCSSProperty* CompressedProperties() const {
- return (CompressedCSSProperty*)(Values() + mNumProps);
- }
- nsCSSValue* ValueAtIndex(uint32_t i) const {
- MOZ_ASSERT(i < mNumProps, "value index out of range");
- return Values() + i;
- }
- nsCSSPropertyID PropertyAtIndex(uint32_t i) const {
- MOZ_ASSERT(i < mNumProps, "property index out of range");
- nsCSSPropertyID prop = (nsCSSPropertyID)CompressedProperties()[i];
- MOZ_ASSERT(!nsCSSProps::IsShorthand(prop), "out of range");
- return prop;
- }
- void CopyValueToIndex(uint32_t i, nsCSSValue* aValue) {
- new (ValueAtIndex(i)) nsCSSValue(*aValue);
- }
- void RawCopyValueToIndex(uint32_t i, nsCSSValue* aValue) {
- memcpy(ValueAtIndex(i), aValue, sizeof(nsCSSValue));
- }
- void SetPropertyAtIndex(uint32_t i, nsCSSPropertyID aProperty) {
- MOZ_ASSERT(i < mNumProps, "set property index out of range");
- CompressedProperties()[i] = (CompressedCSSProperty)aProperty;
- }
- void SetNumPropsToZero() {
- mNumProps = 0;
- }
- };
- // Make sure the values and properties are aligned appropriately. (These
- // assertions are stronger than necessary to keep them simple.)
- static_assert(sizeof(nsCSSCompressedDataBlock) == 8,
- "nsCSSCompressedDataBlock's size has changed");
- static_assert(NS_ALIGNMENT_OF(nsCSSValue) == 4 || NS_ALIGNMENT_OF(nsCSSValue) == 8,
- "nsCSSValue doesn't align with nsCSSCompressedDataBlock");
- static_assert(NS_ALIGNMENT_OF(nsCSSCompressedDataBlock::CompressedCSSProperty) == 2,
- "CompressedCSSProperty doesn't align with nsCSSValue");
- // Make sure that sizeof(CompressedCSSProperty) is big enough.
- static_assert(eCSSProperty_COUNT_no_shorthands <=
- nsCSSCompressedDataBlock::MaxCompressedCSSProperty,
- "nsCSSPropertyID doesn't fit in StoredSizeOfCSSProperty");
- class nsCSSExpandedDataBlock
- {
- friend class nsCSSCompressedDataBlock;
- public:
- nsCSSExpandedDataBlock();
- ~nsCSSExpandedDataBlock();
- private:
- /* Property storage may not be accessed directly; use AddLonghandProperty
- * and friends.
- */
- nsCSSValue mValues[eCSSProperty_COUNT_no_shorthands];
- public:
- /**
- * Transfer all of the state from a pair of compressed data blocks
- * to this expanded block. This expanded block must be clear
- * beforehand.
- *
- * This method DELETES both of the compressed data blocks it is
- * passed. (This is necessary because ownership of sub-objects
- * is transferred to the expanded block.)
- */
- void Expand(nsCSSCompressedDataBlock *aNormalBlock,
- nsCSSCompressedDataBlock *aImportantBlock);
- /**
- * Allocate new compressed blocks and transfer all of the state
- * from this expanded block to the new blocks, clearing this
- * expanded block. A normal block will always be allocated, but
- * an important block will only be allocated if there are
- * !important properties in the expanded block; otherwise
- * |*aImportantBlock| will be set to null.
- *
- * aOrder is an array of nsCSSPropertyID values specifying the order
- * to store values in the two data blocks.
- */
- void Compress(nsCSSCompressedDataBlock **aNormalBlock,
- nsCSSCompressedDataBlock **aImportantBlock,
- const nsTArray<uint32_t>& aOrder);
- /**
- * Copy a value into this expanded block. This does NOT destroy
- * the source value object. |aProperty| cannot be a shorthand.
- */
- void AddLonghandProperty(nsCSSPropertyID aProperty, const nsCSSValue& aValue);
- /**
- * Clear the state of this expanded block.
- */
- void Clear();
- /**
- * Clear the data for the given property (including the set and
- * important bits). Can be used with shorthand properties.
- */
- void ClearProperty(nsCSSPropertyID aPropID);
- /**
- * Same as ClearProperty, but faster and cannot be used with shorthands.
- */
- void ClearLonghandProperty(nsCSSPropertyID aPropID);
- /**
- * Transfer the state for |aPropID| (which may be a shorthand)
- * from |aFromBlock| to this block. The property being transferred
- * is !important if |aIsImportant| is true, and should replace an
- * existing !important property regardless of its own importance
- * if |aOverrideImportant| is true. |aEnabledState| is used to
- * determine which longhand components of |aPropID| (if it is a
- * shorthand) to transfer.
- *
- * Returns true if something changed, false otherwise. Calls
- * |ValueAppended| on |aDeclaration| if the property was not
- * previously set, or in any case if |aMustCallValueAppended| is true.
- * Calls |SetDocumentAndPageUseCounter| on |aSheetDocument| if it is
- * non-null and |aPropID| has a use counter.
- */
- bool TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
- nsCSSPropertyID aPropID,
- mozilla::CSSEnabledState aEnabledState,
- bool aIsImportant,
- bool aOverrideImportant,
- bool aMustCallValueAppended,
- mozilla::css::Declaration* aDeclaration,
- nsIDocument* aSheetDocument);
- /**
- * Copies the values for aPropID into the specified aRuleData object.
- *
- * This is used for copying parsed-at-computed-value-time properties
- * that had variable references. aPropID must be a longhand property.
- */
- void MapRuleInfoInto(nsCSSPropertyID aPropID, nsRuleData* aRuleData) const;
- void AssertInitialState() {
- #ifdef DEBUG
- DoAssertInitialState();
- #endif
- }
- private:
- /**
- * Compute the number of properties that will be present in the
- * result of |Compress|.
- */
- void ComputeNumProps(uint32_t* aNumPropsNormal,
- uint32_t* aNumPropsImportant);
- void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant);
- /**
- * Worker for TransferFromBlock; cannot be used with shorthands.
- */
- bool DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
- nsCSSPropertyID aPropID,
- bool aIsImportant,
- bool aOverrideImportant,
- bool aMustCallValueAppended,
- mozilla::css::Declaration* aDeclaration,
- nsIDocument* aSheetDocument);
- #ifdef DEBUG
- void DoAssertInitialState();
- #endif
- /*
- * mPropertiesSet stores a bit for every property that is present,
- * to optimize compression of blocks with small numbers of
- * properties (the norm) and to allow quickly checking whether a
- * property is set in this block.
- */
- nsCSSPropertyIDSet mPropertiesSet;
- /*
- * mPropertiesImportant indicates which properties are '!important'.
- */
- nsCSSPropertyIDSet mPropertiesImportant;
- /*
- * Return the storage location within |this| of the value of the
- * property |aProperty|.
- */
- nsCSSValue* PropertyAt(nsCSSPropertyID aProperty) {
- MOZ_ASSERT(0 <= aProperty &&
- aProperty < eCSSProperty_COUNT_no_shorthands,
- "property out of range");
- return &mValues[aProperty];
- }
- const nsCSSValue* PropertyAt(nsCSSPropertyID aProperty) const {
- MOZ_ASSERT(0 <= aProperty &&
- aProperty < eCSSProperty_COUNT_no_shorthands,
- "property out of range");
- return &mValues[aProperty];
- }
- void SetPropertyBit(nsCSSPropertyID aProperty) {
- mPropertiesSet.AddProperty(aProperty);
- }
- void ClearPropertyBit(nsCSSPropertyID aProperty) {
- mPropertiesSet.RemoveProperty(aProperty);
- }
- bool HasPropertyBit(nsCSSPropertyID aProperty) {
- return mPropertiesSet.HasProperty(aProperty);
- }
- void SetImportantBit(nsCSSPropertyID aProperty) {
- mPropertiesImportant.AddProperty(aProperty);
- }
- void ClearImportantBit(nsCSSPropertyID aProperty) {
- mPropertiesImportant.RemoveProperty(aProperty);
- }
- bool HasImportantBit(nsCSSPropertyID aProperty) {
- return mPropertiesImportant.HasProperty(aProperty);
- }
- void ClearSets() {
- mPropertiesSet.Empty();
- mPropertiesImportant.Empty();
- }
- };
- #endif /* !defined(nsCSSDataBlock_h__) */
|