nsCSSDataBlock.h 12 KB

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