LCOV - code coverage report
Current view: top level - layout/style - nsCSSDataBlock.h (source / functions) Hit Total Coverage
Test: output.info Lines: 65 65 100.0 %
Date: 2017-07-14 16:53:18 Functions: 22 22 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * compact representation of the property-value pairs within a CSS
       9             :  * declaration, and the code for expanding and compacting it
      10             :  */
      11             : 
      12             : #ifndef nsCSSDataBlock_h__
      13             : #define nsCSSDataBlock_h__
      14             : 
      15             : #include "mozilla/MemoryReporting.h"
      16             : #include "nsCSSProps.h"
      17             : #include "nsCSSPropertyIDSet.h"
      18             : #include "nsCSSValue.h"
      19             : #include "nsStyleStruct.h"
      20             : #include "imgRequestProxy.h"
      21             : 
      22             : struct nsRuleData;
      23             : class nsCSSExpandedDataBlock;
      24             : class nsIDocument;
      25             : 
      26             : namespace mozilla {
      27             : namespace css {
      28             : class Declaration;
      29             : } // namespace css
      30             : } // namespace mozilla
      31             : 
      32             : /**
      33             :  * An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of
      34             :  * property-value data for a CSS declaration block (which we misname a
      35             :  * |css::Declaration|).  Mutation is accomplished through
      36             :  * |nsCSSExpandedDataBlock| or in some cases via direct slot access.
      37             :  */
      38             : class nsCSSCompressedDataBlock
      39             : {
      40             : private:
      41             :   friend class nsCSSExpandedDataBlock;
      42             : 
      43             :   // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock
      44             :   // (in |Compress|) can create compressed data blocks.
      45        3520 :   explicit nsCSSCompressedDataBlock(uint32_t aNumProps)
      46        3520 :     : mStyleBits(0), mNumProps(aNumProps)
      47        3520 :   {}
      48             : 
      49             : public:
      50             :   ~nsCSSCompressedDataBlock();
      51             : 
      52             :   /**
      53             :    * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style
      54             :    * rule using this block for storage.
      55             :    */
      56             :   void MapRuleInfoInto(nsRuleData *aRuleData) const;
      57             : 
      58             :   /**
      59             :    * Return the location at which the *value* for the property is
      60             :    * stored, or null if the block does not contain a value for the
      61             :    * property.
      62             :    *
      63             :    * Inefficient (by design).
      64             :    *
      65             :    * Must not be called for shorthands.
      66             :    */
      67             :   const nsCSSValue* ValueFor(nsCSSPropertyID aProperty) const;
      68             : 
      69             :   /**
      70             :    * Attempt to replace the value for |aProperty| stored in this block
      71             :    * with the matching value stored in |aFromBlock|.
      72             :    * This method will fail (returning false) if |aProperty| is not
      73             :    * already in this block.  It will set |aChanged| to true if it
      74             :    * actually made a change to the block, but regardless, if it
      75             :    * returns true, the value in |aFromBlock| was erased.
      76             :    */
      77             :   bool TryReplaceValue(nsCSSPropertyID aProperty,
      78             :                          nsCSSExpandedDataBlock& aFromBlock,
      79             :                          bool* aChanged);
      80             : 
      81             :   /**
      82             :    * Clone this block, or return null on out-of-memory.
      83             :    */
      84             :   nsCSSCompressedDataBlock* Clone() const;
      85             : 
      86             :   /**
      87             :    * Create a new nsCSSCompressedDataBlock holding no declarations.
      88             :    */
      89             :   static nsCSSCompressedDataBlock* CreateEmptyBlock();
      90             : 
      91             :   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
      92             : 
      93             :   bool HasDefaultBorderImageSlice() const;
      94             :   bool HasDefaultBorderImageWidth() const;
      95             :   bool HasDefaultBorderImageOutset() const;
      96             :   bool HasDefaultBorderImageRepeat() const;
      97             : 
      98         316 :   bool HasInheritedStyleData() const
      99             :   {
     100         316 :     return mStyleBits & NS_STYLE_INHERITED_STRUCT_MASK;
     101             :   }
     102             : 
     103             : private:
     104        3520 :   void* operator new(size_t aBaseSize, uint32_t aNumProps) {
     105        3520 :     MOZ_ASSERT(aBaseSize == sizeof(nsCSSCompressedDataBlock),
     106             :                "unexpected size for nsCSSCompressedDataBlock");
     107        7040 :     return ::operator new(aBaseSize + DataSize(aNumProps));
     108             :   }
     109             : 
     110             : public:
     111             :   // Ideally, |nsCSSPropertyID| would be |enum nsCSSPropertyID : int16_t|.  But
     112             :   // not all of the compilers we use are modern enough to support small
     113             :   // enums.  So we manually squeeze nsCSSPropertyID into 16 bits ourselves.
     114             :   // The static assertion below ensures it fits.
     115             :   typedef int16_t CompressedCSSProperty;
     116             :   static const size_t MaxCompressedCSSProperty = INT16_MAX;
     117             : 
     118             : private:
     119        3520 :   static size_t DataSize(uint32_t aNumProps) {
     120        3520 :     return size_t(aNumProps) *
     121        3520 :            (sizeof(nsCSSValue) + sizeof(CompressedCSSProperty));
     122             :   }
     123             : 
     124             :   int32_t mStyleBits; // the structs for which we have data, according to
     125             :                       // |nsCachedStyleData::GetBitForSID|.
     126             :   uint32_t mNumProps;
     127             :   // nsCSSValue elements are stored after these fields, and
     128             :   // nsCSSPropertyID elements are stored -- each one compressed as a
     129             :   // CompressedCSSProperty -- after the nsCSSValue elements.  Space for them
     130             :   // is allocated in |operator new| above.  The static assertions following
     131             :   // this class make sure that the value and property elements are aligned
     132             :   // appropriately.
     133             : 
     134       70725 :   nsCSSValue* Values() const {
     135       70725 :     return (nsCSSValue*)(this + 1);
     136             :   }
     137             : 
     138       48539 :   CompressedCSSProperty* CompressedProperties() const {
     139       48539 :     return (CompressedCSSProperty*)(Values() + mNumProps);
     140             :   }
     141             : 
     142       22186 :   nsCSSValue* ValueAtIndex(uint32_t i) const {
     143       22186 :     MOZ_ASSERT(i < mNumProps, "value index out of range");
     144       22186 :     return Values() + i;
     145             :   }
     146             : 
     147       35557 :   nsCSSPropertyID PropertyAtIndex(uint32_t i) const {
     148       35557 :     MOZ_ASSERT(i < mNumProps, "property index out of range");
     149       35557 :     nsCSSPropertyID prop = (nsCSSPropertyID)CompressedProperties()[i];
     150       35557 :     MOZ_ASSERT(!nsCSSProps::IsShorthand(prop), "out of range");
     151       35557 :     return prop;
     152             :   }
     153             : 
     154          48 :   void CopyValueToIndex(uint32_t i, nsCSSValue* aValue) {
     155          48 :     new (ValueAtIndex(i)) nsCSSValue(*aValue);
     156          48 :   }
     157             : 
     158       12934 :   void RawCopyValueToIndex(uint32_t i, nsCSSValue* aValue) {
     159       12934 :     memcpy(ValueAtIndex(i), aValue, sizeof(nsCSSValue));
     160       12934 :   }
     161             : 
     162       12982 :   void SetPropertyAtIndex(uint32_t i, nsCSSPropertyID aProperty) {
     163       12982 :     MOZ_ASSERT(i < mNumProps, "set property index out of range");
     164       12982 :     CompressedProperties()[i] = (CompressedCSSProperty)aProperty;
     165       12982 :   }
     166             : 
     167         116 :   void SetNumPropsToZero() {
     168         116 :     mNumProps = 0;
     169         116 :   }
     170             : };
     171             : 
     172             : // Make sure the values and properties are aligned appropriately.  (These
     173             : // assertions are stronger than necessary to keep them simple.)
     174             : static_assert(sizeof(nsCSSCompressedDataBlock) == 8,
     175             :               "nsCSSCompressedDataBlock's size has changed");
     176             : static_assert(NS_ALIGNMENT_OF(nsCSSValue) == 4 || NS_ALIGNMENT_OF(nsCSSValue) == 8,
     177             :               "nsCSSValue doesn't align with nsCSSCompressedDataBlock");
     178             : static_assert(NS_ALIGNMENT_OF(nsCSSCompressedDataBlock::CompressedCSSProperty) == 2,
     179             :               "CompressedCSSProperty doesn't align with nsCSSValue");
     180             : 
     181             : // Make sure that sizeof(CompressedCSSProperty) is big enough.
     182             : static_assert(eCSSProperty_COUNT_no_shorthands <=
     183             :               nsCSSCompressedDataBlock::MaxCompressedCSSProperty,
     184             :               "nsCSSPropertyID doesn't fit in StoredSizeOfCSSProperty");
     185             : 
     186             : class nsCSSExpandedDataBlock
     187             : {
     188             :   friend class nsCSSCompressedDataBlock;
     189             : 
     190             : public:
     191             :   nsCSSExpandedDataBlock();
     192             :   ~nsCSSExpandedDataBlock();
     193             : 
     194             : private:
     195             :   /* Property storage may not be accessed directly; use AddLonghandProperty
     196             :    * and friends.
     197             :    */
     198             :   nsCSSValue mValues[eCSSProperty_COUNT_no_shorthands];
     199             : 
     200             : public:
     201             :   /**
     202             :    * Transfer all of the state from a pair of compressed data blocks
     203             :    * to this expanded block.  This expanded block must be clear
     204             :    * beforehand.
     205             :    *
     206             :    * This method DELETES both of the compressed data blocks it is
     207             :    * passed.  (This is necessary because ownership of sub-objects
     208             :    * is transferred to the expanded block.)
     209             :    */
     210             :   void Expand(nsCSSCompressedDataBlock *aNormalBlock,
     211             :               nsCSSCompressedDataBlock *aImportantBlock);
     212             : 
     213             :   /**
     214             :    * Allocate new compressed blocks and transfer all of the state
     215             :    * from this expanded block to the new blocks, clearing this
     216             :    * expanded block.  A normal block will always be allocated, but
     217             :    * an important block will only be allocated if there are
     218             :    * !important properties in the expanded block; otherwise
     219             :    * |*aImportantBlock| will be set to null.
     220             :    *
     221             :    * aOrder is an array of nsCSSPropertyID values specifying the order
     222             :    * to store values in the two data blocks.
     223             :    */
     224             :   void Compress(nsCSSCompressedDataBlock **aNormalBlock,
     225             :                 nsCSSCompressedDataBlock **aImportantBlock,
     226             :                 const nsTArray<uint32_t>& aOrder);
     227             : 
     228             :   /**
     229             :    * Copy a value into this expanded block.  This does NOT destroy
     230             :    * the source value object.  |aProperty| cannot be a shorthand.
     231             :    */
     232             :   void AddLonghandProperty(nsCSSPropertyID aProperty, const nsCSSValue& aValue);
     233             : 
     234             :   /**
     235             :    * Clear the state of this expanded block.
     236             :    */
     237             :   void Clear();
     238             : 
     239             :   /**
     240             :    * Clear the data for the given property (including the set and
     241             :    * important bits).  Can be used with shorthand properties.
     242             :    */
     243             :   void ClearProperty(nsCSSPropertyID aPropID);
     244             : 
     245             :   /**
     246             :    * Same as ClearProperty, but faster and cannot be used with shorthands.
     247             :    */
     248             :   void ClearLonghandProperty(nsCSSPropertyID aPropID);
     249             : 
     250             :   /**
     251             :    * Transfer the state for |aPropID| (which may be a shorthand)
     252             :    * from |aFromBlock| to this block.  The property being transferred
     253             :    * is !important if |aIsImportant| is true, and should replace an
     254             :    * existing !important property regardless of its own importance
     255             :    * if |aOverrideImportant| is true.  |aEnabledState| is used to
     256             :    * determine which longhand components of |aPropID| (if it is a
     257             :    * shorthand) to transfer.
     258             :    *
     259             :    * Returns true if something changed, false otherwise.  Calls
     260             :    * |ValueAppended| on |aDeclaration| if the property was not
     261             :    * previously set, or in any case if |aMustCallValueAppended| is true.
     262             :    * Calls |SetDocumentAndPageUseCounter| on |aSheetDocument| if it is
     263             :    * non-null and |aPropID| has a use counter.
     264             :    */
     265             :   bool TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
     266             :                          nsCSSPropertyID aPropID,
     267             :                          mozilla::CSSEnabledState aEnabledState,
     268             :                          bool aIsImportant,
     269             :                          bool aOverrideImportant,
     270             :                          bool aMustCallValueAppended,
     271             :                          mozilla::css::Declaration* aDeclaration,
     272             :                          nsIDocument* aSheetDocument);
     273             : 
     274             :   /**
     275             :    * Copies the values for aPropID into the specified aRuleData object.
     276             :    *
     277             :    * This is used for copying parsed-at-computed-value-time properties
     278             :    * that had variable references.  aPropID must be a longhand property.
     279             :    */
     280             :   void MapRuleInfoInto(nsCSSPropertyID aPropID, nsRuleData* aRuleData) const;
     281             : 
     282       21135 :   void AssertInitialState() {
     283             : #ifdef DEBUG
     284       21135 :     DoAssertInitialState();
     285             : #endif
     286       21135 :   }
     287             : 
     288             : private:
     289             :   /**
     290             :    * Compute the number of properties that will be present in the
     291             :    * result of |Compress|.
     292             :    */
     293             :   void ComputeNumProps(uint32_t* aNumPropsNormal,
     294             :                        uint32_t* aNumPropsImportant);
     295             : 
     296             :   void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant);
     297             : 
     298             :   /**
     299             :    * Worker for TransferFromBlock; cannot be used with shorthands.
     300             :    */
     301             :   bool DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
     302             :                              nsCSSPropertyID aPropID,
     303             :                              bool aIsImportant,
     304             :                              bool aOverrideImportant,
     305             :                              bool aMustCallValueAppended,
     306             :                              mozilla::css::Declaration* aDeclaration,
     307             :                              nsIDocument* aSheetDocument);
     308             : 
     309             : #ifdef DEBUG
     310             :   void DoAssertInitialState();
     311             : #endif
     312             : 
     313             :   /*
     314             :    * mPropertiesSet stores a bit for every property that is present,
     315             :    * to optimize compression of blocks with small numbers of
     316             :    * properties (the norm) and to allow quickly checking whether a
     317             :    * property is set in this block.
     318             :    */
     319             :   nsCSSPropertyIDSet mPropertiesSet;
     320             :   /*
     321             :    * mPropertiesImportant indicates which properties are '!important'.
     322             :    */
     323             :   nsCSSPropertyIDSet mPropertiesImportant;
     324             : 
     325             :   /*
     326             :    * Return the storage location within |this| of the value of the
     327             :    * property |aProperty|.
     328             :    */
     329     6879484 :   nsCSSValue* PropertyAt(nsCSSPropertyID aProperty) {
     330     6879484 :     MOZ_ASSERT(0 <= aProperty &&
     331             :                aProperty < eCSSProperty_COUNT_no_shorthands,
     332             :                "property out of range");
     333     6879484 :     return &mValues[aProperty];
     334             :   }
     335         883 :   const nsCSSValue* PropertyAt(nsCSSPropertyID aProperty) const {
     336         883 :     MOZ_ASSERT(0 <= aProperty &&
     337             :                aProperty < eCSSProperty_COUNT_no_shorthands,
     338             :                "property out of range");
     339         883 :     return &mValues[aProperty];
     340             :   }
     341             : 
     342       30652 :   void SetPropertyBit(nsCSSPropertyID aProperty) {
     343       30652 :     mPropertiesSet.AddProperty(aProperty);
     344       30652 :   }
     345             : 
     346       17396 :   void ClearPropertyBit(nsCSSPropertyID aProperty) {
     347       17396 :     mPropertiesSet.RemoveProperty(aProperty);
     348       17396 :   }
     349             : 
     350       13133 :   bool HasPropertyBit(nsCSSPropertyID aProperty) {
     351       13133 :     return mPropertiesSet.HasProperty(aProperty);
     352             :   }
     353             : 
     354        1031 :   void SetImportantBit(nsCSSPropertyID aProperty) {
     355        1031 :     mPropertiesImportant.AddProperty(aProperty);
     356        1031 :   }
     357             : 
     358        4400 :   void ClearImportantBit(nsCSSPropertyID aProperty) {
     359        4400 :     mPropertiesImportant.RemoveProperty(aProperty);
     360        4400 :   }
     361             : 
     362       12992 :   bool HasImportantBit(nsCSSPropertyID aProperty) {
     363       12992 :     return mPropertiesImportant.HasProperty(aProperty);
     364             :   }
     365             : 
     366        3118 :   void ClearSets() {
     367        3118 :     mPropertiesSet.Empty();
     368        3118 :     mPropertiesImportant.Empty();
     369        3118 :   }
     370             : };
     371             : 
     372             : #endif /* !defined(nsCSSDataBlock_h__) */

Generated by: LCOV version 1.13