layout/style/nsCSSDataBlock.h

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

     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/. */
     6 /*
     7  * compact representation of the property-value pairs within a CSS
     8  * declaration, and the code for expanding and compacting it
     9  */
    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"
    20 struct nsRuleData;
    21 class nsCSSExpandedDataBlock;
    23 namespace mozilla {
    24 namespace css {
    25 class Declaration;
    26 }
    27 }
    29 /**
    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.
    34  */
    35 class nsCSSCompressedDataBlock {
    36 private:
    37     friend class nsCSSExpandedDataBlock;
    39     // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock
    40     // (in |Compress|) can create compressed data blocks.
    41     nsCSSCompressedDataBlock(uint32_t aNumProps)
    42       : mStyleBits(0), mNumProps(aNumProps)
    43     {}
    45 public:
    46     ~nsCSSCompressedDataBlock();
    48     /**
    49      * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style
    50      * rule using this block for storage.
    51      */
    52     void MapRuleInfoInto(nsRuleData *aRuleData) const;
    54     /**
    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
    57      * property.
    58      *
    59      * Inefficient (by design).
    60      *
    61      * Must not be called for shorthands.
    62      */
    63     const nsCSSValue* ValueFor(nsCSSProperty aProperty) const;
    65     /**
    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.
    72      */
    73     bool TryReplaceValue(nsCSSProperty aProperty,
    74                            nsCSSExpandedDataBlock& aFromBlock,
    75                            bool* aChanged);
    77     /**
    78      * Clone this block, or return null on out-of-memory.
    79      */
    80     nsCSSCompressedDataBlock* Clone() const;
    82     /**
    83      * Create a new nsCSSCompressedDataBlock holding no declarations.
    84      */
    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;
    94 private:
    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));
    99     }
   101 public:
   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;
   109 private:
   110     static size_t DataSize(uint32_t aNumProps) {
   111         return size_t(aNumProps) *
   112                (sizeof(nsCSSValue) + sizeof(CompressedCSSProperty));
   113     }
   115     int32_t mStyleBits; // the structs for which we have data, according to
   116                         // |nsCachedStyleData::GetBitForSID|.
   117     uint32_t mNumProps;
   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
   123     // appropriately.
   125     nsCSSValue* Values() const {
   126         return (nsCSSValue*)(this + 1);
   127     }
   129     CompressedCSSProperty* CompressedProperties() const {
   130         return (CompressedCSSProperty*)(Values() + mNumProps);
   131     }
   133     nsCSSValue* ValueAtIndex(uint32_t i) const {
   134         NS_ABORT_IF_FALSE(i < mNumProps, "value index out of range");
   135         return Values() + i;
   136     }
   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");
   142         return prop;
   143     }
   145     void CopyValueToIndex(uint32_t i, nsCSSValue* aValue) {
   146         new (ValueAtIndex(i)) nsCSSValue(*aValue);
   147     }
   149     void RawCopyValueToIndex(uint32_t i, nsCSSValue* aValue) {
   150         memcpy(ValueAtIndex(i), aValue, sizeof(nsCSSValue));
   151     }
   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;
   156     }
   158     void SetNumPropsToZero() {
   159         mNumProps = 0;
   160     }
   161 };
   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;
   180 public:
   181     nsCSSExpandedDataBlock();
   182     ~nsCSSExpandedDataBlock();
   184 private:
   185     /* Property storage may not be accessed directly; use AddLonghandProperty
   186      * and friends.
   187      */
   188     nsCSSValue mValues[eCSSProperty_COUNT_no_shorthands];
   190 public:
   191     /**
   192      * Transfer all of the state from a pair of compressed data blocks
   193      * to this expanded block.  This expanded block must be clear
   194      * beforehand.
   195      *
   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.)
   199      */
   200     void Expand(nsCSSCompressedDataBlock *aNormalBlock,
   201                 nsCSSCompressedDataBlock *aImportantBlock);
   203     /**
   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.
   210      */
   211     void Compress(nsCSSCompressedDataBlock **aNormalBlock,
   212                   nsCSSCompressedDataBlock **aImportantBlock);
   214     /**
   215      * Copy a value into this expanded block.  This does NOT destroy
   216      * the source value object.  |aProperty| cannot be a shorthand.
   217      */
   218     void AddLonghandProperty(nsCSSProperty aProperty, const nsCSSValue& aValue);
   220     /**
   221      * Clear the state of this expanded block.
   222      */
   223     void Clear();
   225     /**
   226      * Clear the data for the given property (including the set and
   227      * important bits).  Can be used with shorthand properties.
   228      */
   229     void ClearProperty(nsCSSProperty aPropID);
   231     /**
   232      * Same as ClearProperty, but faster and cannot be used with shorthands.
   233      */
   234     void ClearLonghandProperty(nsCSSProperty aPropID);
   236     /**
   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.
   242      *
   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.
   246      */
   247     bool TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
   248                              nsCSSProperty aPropID,
   249                              bool aIsImportant,
   250                              bool aOverrideImportant,
   251                              bool aMustCallValueAppended,
   252                              mozilla::css::Declaration* aDeclaration);
   254     /**
   255      * Copies the values for aPropID into the specified aRuleData object.
   256      *
   257      * This is used for copying parsed-at-computed-value-time properties
   258      * that had variable references.  aPropID must be a longhand property.
   259      */
   260     void MapRuleInfoInto(nsCSSProperty aPropID, nsRuleData* aRuleData) const;
   262     void AssertInitialState() {
   263 #ifdef DEBUG
   264         DoAssertInitialState();
   265 #endif
   266     }
   268 private:
   269     /**
   270      * Compute the number of properties that will be present in the
   271      * result of |Compress|.
   272      */
   273     void ComputeNumProps(uint32_t* aNumPropsNormal,
   274                          uint32_t* aNumPropsImportant);
   276     void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant);
   278     /**
   279      * Worker for TransferFromBlock; cannot be used with shorthands.
   280      */
   281     bool DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
   282                                nsCSSProperty aPropID,
   283                                bool aIsImportant,
   284                                bool aOverrideImportant,
   285                                bool aMustCallValueAppended,
   286                                mozilla::css::Declaration* aDeclaration);
   288 #ifdef DEBUG
   289     void DoAssertInitialState();
   290 #endif
   292     /*
   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.
   297      */
   298     nsCSSPropertySet mPropertiesSet;
   299     /*
   300      * mPropertiesImportant indicates which properties are '!important'.
   301      */
   302     nsCSSPropertySet mPropertiesImportant;
   304     /*
   305      * Return the storage location within |this| of the value of the
   306      * property |aProperty|.
   307      */
   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];
   313     }
   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];
   319     }
   321     void SetPropertyBit(nsCSSProperty aProperty) {
   322         mPropertiesSet.AddProperty(aProperty);
   323     }
   325     void ClearPropertyBit(nsCSSProperty aProperty) {
   326         mPropertiesSet.RemoveProperty(aProperty);
   327     }
   329     bool HasPropertyBit(nsCSSProperty aProperty) {
   330         return mPropertiesSet.HasProperty(aProperty);
   331     }
   333     void SetImportantBit(nsCSSProperty aProperty) {
   334         mPropertiesImportant.AddProperty(aProperty);
   335     }
   337     void ClearImportantBit(nsCSSProperty aProperty) {
   338         mPropertiesImportant.RemoveProperty(aProperty);
   339     }
   341     bool HasImportantBit(nsCSSProperty aProperty) {
   342         return mPropertiesImportant.HasProperty(aProperty);
   343     }
   345     void ClearSets() {
   346         mPropertiesSet.Empty();
   347         mPropertiesImportant.Empty();
   348     }
   349 };
   351 #endif /* !defined(nsCSSDataBlock_h__) */

mercurial