1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsCSSDataBlock.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,351 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * compact representation of the property-value pairs within a CSS 1.11 + * declaration, and the code for expanding and compacting it 1.12 + */ 1.13 + 1.14 +#ifndef nsCSSDataBlock_h__ 1.15 +#define nsCSSDataBlock_h__ 1.16 + 1.17 +#include "mozilla/MemoryReporting.h" 1.18 +#include "nsCSSProps.h" 1.19 +#include "nsCSSPropertySet.h" 1.20 +#include "nsCSSValue.h" 1.21 +#include "imgRequestProxy.h" 1.22 + 1.23 +struct nsRuleData; 1.24 +class nsCSSExpandedDataBlock; 1.25 + 1.26 +namespace mozilla { 1.27 +namespace css { 1.28 +class Declaration; 1.29 +} 1.30 +} 1.31 + 1.32 +/** 1.33 + * An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of 1.34 + * property-value data for a CSS declaration block (which we misname a 1.35 + * |css::Declaration|). Mutation is accomplished through 1.36 + * |nsCSSExpandedDataBlock| or in some cases via direct slot access. 1.37 + */ 1.38 +class nsCSSCompressedDataBlock { 1.39 +private: 1.40 + friend class nsCSSExpandedDataBlock; 1.41 + 1.42 + // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock 1.43 + // (in |Compress|) can create compressed data blocks. 1.44 + nsCSSCompressedDataBlock(uint32_t aNumProps) 1.45 + : mStyleBits(0), mNumProps(aNumProps) 1.46 + {} 1.47 + 1.48 +public: 1.49 + ~nsCSSCompressedDataBlock(); 1.50 + 1.51 + /** 1.52 + * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style 1.53 + * rule using this block for storage. 1.54 + */ 1.55 + void MapRuleInfoInto(nsRuleData *aRuleData) const; 1.56 + 1.57 + /** 1.58 + * Return the location at which the *value* for the property is 1.59 + * stored, or null if the block does not contain a value for the 1.60 + * property. 1.61 + * 1.62 + * Inefficient (by design). 1.63 + * 1.64 + * Must not be called for shorthands. 1.65 + */ 1.66 + const nsCSSValue* ValueFor(nsCSSProperty aProperty) const; 1.67 + 1.68 + /** 1.69 + * Attempt to replace the value for |aProperty| stored in this block 1.70 + * with the matching value stored in |aFromBlock|. 1.71 + * This method will fail (returning false) if |aProperty| is not 1.72 + * already in this block. It will set |aChanged| to true if it 1.73 + * actually made a change to the block, but regardless, if it 1.74 + * returns true, the value in |aFromBlock| was erased. 1.75 + */ 1.76 + bool TryReplaceValue(nsCSSProperty aProperty, 1.77 + nsCSSExpandedDataBlock& aFromBlock, 1.78 + bool* aChanged); 1.79 + 1.80 + /** 1.81 + * Clone this block, or return null on out-of-memory. 1.82 + */ 1.83 + nsCSSCompressedDataBlock* Clone() const; 1.84 + 1.85 + /** 1.86 + * Create a new nsCSSCompressedDataBlock holding no declarations. 1.87 + */ 1.88 + static nsCSSCompressedDataBlock* CreateEmptyBlock(); 1.89 + 1.90 + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 1.91 + 1.92 + bool HasDefaultBorderImageSlice() const; 1.93 + bool HasDefaultBorderImageWidth() const; 1.94 + bool HasDefaultBorderImageOutset() const; 1.95 + bool HasDefaultBorderImageRepeat() const; 1.96 + 1.97 +private: 1.98 + void* operator new(size_t aBaseSize, uint32_t aNumProps) { 1.99 + NS_ABORT_IF_FALSE(aBaseSize == sizeof(nsCSSCompressedDataBlock), 1.100 + "unexpected size for nsCSSCompressedDataBlock"); 1.101 + return ::operator new(aBaseSize + DataSize(aNumProps)); 1.102 + } 1.103 + 1.104 +public: 1.105 + // Ideally, |nsCSSProperty| would be |enum nsCSSProperty : int16_t|. But 1.106 + // not all of the compilers we use are modern enough to support small 1.107 + // enums. So we manually squeeze nsCSSProperty into 16 bits ourselves. 1.108 + // The static assertion below ensures it fits. 1.109 + typedef int16_t CompressedCSSProperty; 1.110 + static const size_t MaxCompressedCSSProperty = INT16_MAX; 1.111 + 1.112 +private: 1.113 + static size_t DataSize(uint32_t aNumProps) { 1.114 + return size_t(aNumProps) * 1.115 + (sizeof(nsCSSValue) + sizeof(CompressedCSSProperty)); 1.116 + } 1.117 + 1.118 + int32_t mStyleBits; // the structs for which we have data, according to 1.119 + // |nsCachedStyleData::GetBitForSID|. 1.120 + uint32_t mNumProps; 1.121 + // nsCSSValue elements are stored after these fields, and 1.122 + // nsCSSProperty elements are stored -- each one compressed as a 1.123 + // CompressedCSSProperty -- after the nsCSSValue elements. Space for them 1.124 + // is allocated in |operator new| above. The static assertions following 1.125 + // this class make sure that the value and property elements are aligned 1.126 + // appropriately. 1.127 + 1.128 + nsCSSValue* Values() const { 1.129 + return (nsCSSValue*)(this + 1); 1.130 + } 1.131 + 1.132 + CompressedCSSProperty* CompressedProperties() const { 1.133 + return (CompressedCSSProperty*)(Values() + mNumProps); 1.134 + } 1.135 + 1.136 + nsCSSValue* ValueAtIndex(uint32_t i) const { 1.137 + NS_ABORT_IF_FALSE(i < mNumProps, "value index out of range"); 1.138 + return Values() + i; 1.139 + } 1.140 + 1.141 + nsCSSProperty PropertyAtIndex(uint32_t i) const { 1.142 + NS_ABORT_IF_FALSE(i < mNumProps, "property index out of range"); 1.143 + nsCSSProperty prop = (nsCSSProperty)CompressedProperties()[i]; 1.144 + NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(prop), "out of range"); 1.145 + return prop; 1.146 + } 1.147 + 1.148 + void CopyValueToIndex(uint32_t i, nsCSSValue* aValue) { 1.149 + new (ValueAtIndex(i)) nsCSSValue(*aValue); 1.150 + } 1.151 + 1.152 + void RawCopyValueToIndex(uint32_t i, nsCSSValue* aValue) { 1.153 + memcpy(ValueAtIndex(i), aValue, sizeof(nsCSSValue)); 1.154 + } 1.155 + 1.156 + void SetPropertyAtIndex(uint32_t i, nsCSSProperty aProperty) { 1.157 + NS_ABORT_IF_FALSE(i < mNumProps, "set property index out of range"); 1.158 + CompressedProperties()[i] = (CompressedCSSProperty)aProperty; 1.159 + } 1.160 + 1.161 + void SetNumPropsToZero() { 1.162 + mNumProps = 0; 1.163 + } 1.164 +}; 1.165 + 1.166 +// Make sure the values and properties are aligned appropriately. (These 1.167 +// assertions are stronger than necessary to keep them simple.) 1.168 +static_assert(sizeof(nsCSSCompressedDataBlock) == 8, 1.169 + "nsCSSCompressedDataBlock's size has changed"); 1.170 +static_assert(NS_ALIGNMENT_OF(nsCSSValue) == 4 || NS_ALIGNMENT_OF(nsCSSValue) == 8, 1.171 + "nsCSSValue doesn't align with nsCSSCompressedDataBlock"); 1.172 +static_assert(NS_ALIGNMENT_OF(nsCSSCompressedDataBlock::CompressedCSSProperty) == 2, 1.173 + "CompressedCSSProperty doesn't align with nsCSSValue"); 1.174 + 1.175 +// Make sure that sizeof(CompressedCSSProperty) is big enough. 1.176 +static_assert(eCSSProperty_COUNT_no_shorthands <= 1.177 + nsCSSCompressedDataBlock::MaxCompressedCSSProperty, 1.178 + "nsCSSProperty doesn't fit in StoredSizeOfCSSProperty"); 1.179 + 1.180 +class nsCSSExpandedDataBlock { 1.181 + friend class nsCSSCompressedDataBlock; 1.182 + 1.183 +public: 1.184 + nsCSSExpandedDataBlock(); 1.185 + ~nsCSSExpandedDataBlock(); 1.186 + 1.187 +private: 1.188 + /* Property storage may not be accessed directly; use AddLonghandProperty 1.189 + * and friends. 1.190 + */ 1.191 + nsCSSValue mValues[eCSSProperty_COUNT_no_shorthands]; 1.192 + 1.193 +public: 1.194 + /** 1.195 + * Transfer all of the state from a pair of compressed data blocks 1.196 + * to this expanded block. This expanded block must be clear 1.197 + * beforehand. 1.198 + * 1.199 + * This method DELETES both of the compressed data blocks it is 1.200 + * passed. (This is necessary because ownership of sub-objects 1.201 + * is transferred to the expanded block.) 1.202 + */ 1.203 + void Expand(nsCSSCompressedDataBlock *aNormalBlock, 1.204 + nsCSSCompressedDataBlock *aImportantBlock); 1.205 + 1.206 + /** 1.207 + * Allocate new compressed blocks and transfer all of the state 1.208 + * from this expanded block to the new blocks, clearing this 1.209 + * expanded block. A normal block will always be allocated, but 1.210 + * an important block will only be allocated if there are 1.211 + * !important properties in the expanded block; otherwise 1.212 + * |*aImportantBlock| will be set to null. 1.213 + */ 1.214 + void Compress(nsCSSCompressedDataBlock **aNormalBlock, 1.215 + nsCSSCompressedDataBlock **aImportantBlock); 1.216 + 1.217 + /** 1.218 + * Copy a value into this expanded block. This does NOT destroy 1.219 + * the source value object. |aProperty| cannot be a shorthand. 1.220 + */ 1.221 + void AddLonghandProperty(nsCSSProperty aProperty, const nsCSSValue& aValue); 1.222 + 1.223 + /** 1.224 + * Clear the state of this expanded block. 1.225 + */ 1.226 + void Clear(); 1.227 + 1.228 + /** 1.229 + * Clear the data for the given property (including the set and 1.230 + * important bits). Can be used with shorthand properties. 1.231 + */ 1.232 + void ClearProperty(nsCSSProperty aPropID); 1.233 + 1.234 + /** 1.235 + * Same as ClearProperty, but faster and cannot be used with shorthands. 1.236 + */ 1.237 + void ClearLonghandProperty(nsCSSProperty aPropID); 1.238 + 1.239 + /** 1.240 + * Transfer the state for |aPropID| (which may be a shorthand) 1.241 + * from |aFromBlock| to this block. The property being transferred 1.242 + * is !important if |aIsImportant| is true, and should replace an 1.243 + * existing !important property regardless of its own importance 1.244 + * if |aOverrideImportant| is true. 1.245 + * 1.246 + * Returns true if something changed, false otherwise. Calls 1.247 + * |ValueAppended| on |aDeclaration| if the property was not 1.248 + * previously set, or in any case if |aMustCallValueAppended| is true. 1.249 + */ 1.250 + bool TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock, 1.251 + nsCSSProperty aPropID, 1.252 + bool aIsImportant, 1.253 + bool aOverrideImportant, 1.254 + bool aMustCallValueAppended, 1.255 + mozilla::css::Declaration* aDeclaration); 1.256 + 1.257 + /** 1.258 + * Copies the values for aPropID into the specified aRuleData object. 1.259 + * 1.260 + * This is used for copying parsed-at-computed-value-time properties 1.261 + * that had variable references. aPropID must be a longhand property. 1.262 + */ 1.263 + void MapRuleInfoInto(nsCSSProperty aPropID, nsRuleData* aRuleData) const; 1.264 + 1.265 + void AssertInitialState() { 1.266 +#ifdef DEBUG 1.267 + DoAssertInitialState(); 1.268 +#endif 1.269 + } 1.270 + 1.271 +private: 1.272 + /** 1.273 + * Compute the number of properties that will be present in the 1.274 + * result of |Compress|. 1.275 + */ 1.276 + void ComputeNumProps(uint32_t* aNumPropsNormal, 1.277 + uint32_t* aNumPropsImportant); 1.278 + 1.279 + void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant); 1.280 + 1.281 + /** 1.282 + * Worker for TransferFromBlock; cannot be used with shorthands. 1.283 + */ 1.284 + bool DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock, 1.285 + nsCSSProperty aPropID, 1.286 + bool aIsImportant, 1.287 + bool aOverrideImportant, 1.288 + bool aMustCallValueAppended, 1.289 + mozilla::css::Declaration* aDeclaration); 1.290 + 1.291 +#ifdef DEBUG 1.292 + void DoAssertInitialState(); 1.293 +#endif 1.294 + 1.295 + /* 1.296 + * mPropertiesSet stores a bit for every property that is present, 1.297 + * to optimize compression of blocks with small numbers of 1.298 + * properties (the norm) and to allow quickly checking whether a 1.299 + * property is set in this block. 1.300 + */ 1.301 + nsCSSPropertySet mPropertiesSet; 1.302 + /* 1.303 + * mPropertiesImportant indicates which properties are '!important'. 1.304 + */ 1.305 + nsCSSPropertySet mPropertiesImportant; 1.306 + 1.307 + /* 1.308 + * Return the storage location within |this| of the value of the 1.309 + * property |aProperty|. 1.310 + */ 1.311 + nsCSSValue* PropertyAt(nsCSSProperty aProperty) { 1.312 + NS_ABORT_IF_FALSE(0 <= aProperty && 1.313 + aProperty < eCSSProperty_COUNT_no_shorthands, 1.314 + "property out of range"); 1.315 + return &mValues[aProperty]; 1.316 + } 1.317 + const nsCSSValue* PropertyAt(nsCSSProperty aProperty) const { 1.318 + NS_ABORT_IF_FALSE(0 <= aProperty && 1.319 + aProperty < eCSSProperty_COUNT_no_shorthands, 1.320 + "property out of range"); 1.321 + return &mValues[aProperty]; 1.322 + } 1.323 + 1.324 + void SetPropertyBit(nsCSSProperty aProperty) { 1.325 + mPropertiesSet.AddProperty(aProperty); 1.326 + } 1.327 + 1.328 + void ClearPropertyBit(nsCSSProperty aProperty) { 1.329 + mPropertiesSet.RemoveProperty(aProperty); 1.330 + } 1.331 + 1.332 + bool HasPropertyBit(nsCSSProperty aProperty) { 1.333 + return mPropertiesSet.HasProperty(aProperty); 1.334 + } 1.335 + 1.336 + void SetImportantBit(nsCSSProperty aProperty) { 1.337 + mPropertiesImportant.AddProperty(aProperty); 1.338 + } 1.339 + 1.340 + void ClearImportantBit(nsCSSProperty aProperty) { 1.341 + mPropertiesImportant.RemoveProperty(aProperty); 1.342 + } 1.343 + 1.344 + bool HasImportantBit(nsCSSProperty aProperty) { 1.345 + return mPropertiesImportant.HasProperty(aProperty); 1.346 + } 1.347 + 1.348 + void ClearSets() { 1.349 + mPropertiesSet.Empty(); 1.350 + mPropertiesImportant.Empty(); 1.351 + } 1.352 +}; 1.353 + 1.354 +#endif /* !defined(nsCSSDataBlock_h__) */