Loading layout/style/nsCSSDataBlock.cpp +120 −46 Original line number Original line Diff line number Diff line Loading @@ -48,6 +48,34 @@ namespace css = mozilla::css; namespace css = mozilla::css; enum { CDBValueStorage_advance = sizeof(CDBValueStorage) }; /* * Define a bunch of utility functions for getting the property or any * of the value types when the cursor is at the beginning of the storage * for the property-value pair. The versions taking a non-const cursor * argument return a reference so that the caller can assign into the * result. */ inline nsCSSProperty& PropertyAtCursor(char *aCursor) { return *reinterpret_cast<nsCSSProperty*>(aCursor); } inline nsCSSProperty PropertyAtCursor(const char *aCursor) { return *reinterpret_cast<const nsCSSProperty*>(aCursor); } inline nsCSSValue* ValueAtCursor(char *aCursor) { return & reinterpret_cast<CDBValueStorage*>(aCursor)->value; } inline const nsCSSValue* ValueAtCursor(const char *aCursor) { return & reinterpret_cast<const CDBValueStorage*>(aCursor)->value; } /** /** * Does a fast move of aSource to aDest. The previous value in * Does a fast move of aSource to aDest. The previous value in * aDest is cleanly destroyed, and aSource is cleared. Returns * aDest is cleanly destroyed, and aSource is cleared. Returns Loading Loading @@ -136,13 +164,16 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const nsIDocument* doc = aRuleData->mPresContext->Document(); nsIDocument* doc = aRuleData->mPresContext->Document(); for (PRUint32 i = 0; i < mNumProps; i++) { const char* cursor = Block(); nsCSSProperty iProp = PropertyAtIndex(i); const char* cursor_end = BlockEnd(); while (cursor < cursor_end) { nsCSSProperty iProp = PropertyAtCursor(cursor); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) & if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) & aRuleData->mSIDs) { aRuleData->mSIDs) { nsCSSValue* target = aRuleData->ValueFor(iProp); nsCSSValue* target = aRuleData->ValueFor(iProp); if (target->GetUnit() == eCSSUnit_Null) { if (target->GetUnit() == eCSSUnit_Null) { const nsCSSValue *val = ValueAtIndex(i); const nsCSSValue *val = ValueAtCursor(cursor); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); if (ShouldStartImageLoads(aRuleData, iProp)) { if (ShouldStartImageLoads(aRuleData, iProp)) { TryToStartImageLoad(*val, doc, iProp); TryToStartImageLoad(*val, doc, iProp); Loading @@ -166,7 +197,9 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const } } } } } } cursor += CDBValueStorage_advance; } } NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data"); } } const nsCSSValue* const nsCSSValue* Loading @@ -183,11 +216,17 @@ nsCSSCompressedDataBlock::ValueFor(nsCSSProperty aProperty) const mStyleBits)) mStyleBits)) return nsnull; return nsnull; for (PRUint32 i = 0; i < mNumProps; i++) { const char* cursor = Block(); if (PropertyAtIndex(i) == aProperty) { const char* cursor_end = BlockEnd(); return ValueAtIndex(i); while (cursor < cursor_end) { nsCSSProperty iProp = PropertyAtCursor(cursor); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); if (iProp == aProperty) { return ValueAtCursor(cursor); } } cursor += CDBValueStorage_advance; } } NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data"); return nsnull; return nsnull; } } Loading Loading @@ -215,35 +254,56 @@ nsCSSCompressedDataBlock::TryReplaceValue(nsCSSProperty aProperty, nsCSSCompressedDataBlock* nsCSSCompressedDataBlock* nsCSSCompressedDataBlock::Clone() const nsCSSCompressedDataBlock::Clone() const { { nsAutoPtr<nsCSSCompressedDataBlock> const char *cursor = Block(), *cursor_end = BlockEnd(); result(new(mNumProps) nsCSSCompressedDataBlock(mNumProps)); char *result_cursor; result->mStyleBits = mStyleBits; nsAutoPtr<nsCSSCompressedDataBlock> result (new(cursor_end - cursor) nsCSSCompressedDataBlock()); if (!result) return nsnull; result_cursor = result->Block(); for (PRUint32 i = 0; i < mNumProps; i++) { while (cursor < cursor_end) { result->SetPropertyAtIndex(i, PropertyAtIndex(i)); nsCSSProperty iProp = PropertyAtCursor(cursor); result->CopyValueToIndex(i, ValueAtIndex(i)); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); PropertyAtCursor(result_cursor) = iProp; const nsCSSValue* val = ValueAtCursor(cursor); nsCSSValue *result_val = ValueAtCursor(result_cursor); new (result_val) nsCSSValue(*val); cursor += CDBValueStorage_advance; result_cursor += CDBValueStorage_advance; } } NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data"); result->SetBlockEnd(result_cursor); result->mStyleBits = mStyleBits; NS_ABORT_IF_FALSE(result->DataSize() == DataSize(), "wrong size"); return result.forget(); return result.forget(); } } nsCSSCompressedDataBlock::~nsCSSCompressedDataBlock() nsCSSCompressedDataBlock::~nsCSSCompressedDataBlock() { { for (PRUint32 i = 0; i < mNumProps; i++) { const char* cursor = Block(); #ifdef DEBUG const char* cursor_end = BlockEnd(); (void)PropertyAtIndex(i); // this checks the property is in range while (cursor < cursor_end) { #endif NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(PropertyAtCursor(cursor)), const nsCSSValue* val = ValueAtIndex(i); "out of range"); const nsCSSValue* val = ValueAtCursor(cursor); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); val->~nsCSSValue(); val->~nsCSSValue(); cursor += CDBValueStorage_advance; } } NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data"); } } /* static */ nsCSSCompressedDataBlock* /* static */ nsCSSCompressedDataBlock* nsCSSCompressedDataBlock::CreateEmptyBlock() nsCSSCompressedDataBlock::CreateEmptyBlock() { { nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock(0); nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock(); result->SetBlockEnd(result->Block()); return result; return result; } } Loading @@ -251,8 +311,12 @@ size_t nsCSSCompressedDataBlock::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const nsCSSCompressedDataBlock::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const { { size_t n = aMallocSizeOf(this); size_t n = aMallocSizeOf(this); for (PRUint32 i = 0; i < mNumProps; i++) { n += ValueAtIndex(i)->SizeOfExcludingThis(aMallocSizeOf); const char* cursor = Block(); const char* cursor_end = BlockEnd(); while (cursor < cursor_end) { n += ValueAtCursor(cursor)->SizeOfExcludingThis(aMallocSizeOf); cursor += CDBValueStorage_advance; } } return n; return n; } } Loading @@ -277,8 +341,10 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock, * Save needless copying and allocation by copying the memory * Save needless copying and allocation by copying the memory * corresponding to the stored data in the compressed block. * corresponding to the stored data in the compressed block. */ */ for (PRUint32 i = 0; i < aBlock->mNumProps; i++) { const char* cursor = aBlock->Block(); nsCSSProperty iProp = aBlock->PropertyAtIndex(i); const char* cursor_end = aBlock->BlockEnd(); while (cursor < cursor_end) { nsCSSProperty iProp = PropertyAtCursor(cursor); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); NS_ABORT_IF_FALSE(!HasPropertyBit(iProp), NS_ABORT_IF_FALSE(!HasPropertyBit(iProp), "compressed block has property multiple times"); "compressed block has property multiple times"); Loading @@ -286,7 +352,7 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock, if (aImportant) if (aImportant) SetImportantBit(iProp); SetImportantBit(iProp); const nsCSSValue* val = aBlock->ValueAtIndex(i); const nsCSSValue* val = ValueAtCursor(cursor); nsCSSValue* dest = PropertyAt(iProp); nsCSSValue* dest = PropertyAt(iProp); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); NS_ABORT_IF_FALSE(dest->GetUnit() == eCSSUnit_Null, NS_ABORT_IF_FALSE(dest->GetUnit() == eCSSUnit_Null, Loading @@ -295,11 +361,12 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock, dest->~nsCSSValue(); dest->~nsCSSValue(); #endif #endif memcpy(dest, val, sizeof(nsCSSValue)); memcpy(dest, val, sizeof(nsCSSValue)); cursor += CDBValueStorage_advance; } } NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data"); // Set the number of properties to zero so that we don't destroy the // Don't destroy remnants of what we just copied // remnants of what we just copied. aBlock->SetBlockEnd(aBlock->Block()); aBlock->SetNumPropsToZero(); delete aBlock; delete aBlock; } } Loading @@ -316,11 +383,10 @@ nsCSSExpandedDataBlock::Expand(nsCSSCompressedDataBlock *aNormalBlock, } } } } void nsCSSExpandedDataBlock::ComputeSizeResult nsCSSExpandedDataBlock::ComputeNumProps(PRUint32* aNumPropsNormal, nsCSSExpandedDataBlock::ComputeSize() PRUint32* aNumPropsImportant) { { *aNumPropsNormal = *aNumPropsImportant = 0; ComputeSizeResult result = {0, 0}; for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) { for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) { if (!mPropertiesSet.HasPropertyInChunk(iHigh)) if (!mPropertiesSet.HasPropertyInChunk(iHigh)) continue; continue; Loading @@ -334,11 +400,12 @@ nsCSSExpandedDataBlock::ComputeNumProps(PRUint32* aNumPropsNormal, NS_ABORT_IF_FALSE(PropertyAt(iProp)->GetUnit() != eCSSUnit_Null, NS_ABORT_IF_FALSE(PropertyAt(iProp)->GetUnit() != eCSSUnit_Null, "null value while computing size"); "null value while computing size"); if (mPropertiesImportant.HasPropertyAt(iHigh, iLow)) if (mPropertiesImportant.HasPropertyAt(iHigh, iLow)) (*aNumPropsImportant)++; result.important += CDBValueStorage_advance; else else (*aNumPropsNormal)++; result.normal += CDBValueStorage_advance; } } } } return result; } } void void Loading @@ -346,19 +413,19 @@ nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock, nsCSSCompressedDataBlock **aImportantBlock) nsCSSCompressedDataBlock **aImportantBlock) { { nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important; nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important; PRUint32 i_normal = 0, i_important = 0; char *cursor_normal, *cursor_important; PRUint32 numPropsNormal, numPropsImportant; ComputeSizeResult size = ComputeSize(); ComputeNumProps(&numPropsNormal, &numPropsImportant); result_normal = result_normal = new(size.normal) nsCSSCompressedDataBlock(); new(numPropsNormal) nsCSSCompressedDataBlock(numPropsNormal); cursor_normal = result_normal->Block(); if (numPropsImportant != 0) { if (size.important != 0) { result_important = result_important = new(size.important) nsCSSCompressedDataBlock(); new(numPropsImportant) nsCSSCompressedDataBlock(numPropsImportant); cursor_important = result_important->Block(); } else { } else { result_important = nsnull; result_important = nsnull; cursor_important = nsnull; } } /* /* Loading @@ -376,25 +443,32 @@ nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock, NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); bool important = bool important = mPropertiesImportant.HasPropertyAt(iHigh, iLow); mPropertiesImportant.HasPropertyAt(iHigh, iLow); char *&cursor = important ? cursor_important : cursor_normal; nsCSSCompressedDataBlock *result = nsCSSCompressedDataBlock *result = important ? result_important : result_normal; important ? result_important : result_normal; PRUint32* ip = important ? &i_important : &i_normal; nsCSSValue* val = PropertyAt(iProp); nsCSSValue* val = PropertyAt(iProp); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "Null value while compressing"); "Null value while compressing"); result->SetPropertyAtIndex(*ip, iProp); CDBValueStorage *storage = result->RawCopyValueToIndex(*ip, val); reinterpret_cast<CDBValueStorage*>(cursor); storage->property = iProp; memcpy(&storage->value, val, sizeof(nsCSSValue)); new (val) nsCSSValue(); new (val) nsCSSValue(); (*ip)++; cursor += CDBValueStorage_advance; result->mStyleBits |= result->mStyleBits |= nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]); nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]); } } } } NS_ABORT_IF_FALSE(numPropsNormal == i_normal, "bad numProps"); result_normal->SetBlockEnd(cursor_normal); NS_ABORT_IF_FALSE(result_normal->DataSize() == ptrdiff_t(size.normal), "size miscalculation"); if (result_important) { if (result_important) { NS_ABORT_IF_FALSE(numPropsImportant == i_important, "bad numProps"); result_important->SetBlockEnd(cursor_important); NS_ABORT_IF_FALSE(result_important->DataSize() == ptrdiff_t(size.important), "size miscalculation"); } } ClearSets(); ClearSets(); Loading layout/style/nsCSSDataBlock.h +45 −76 Original line number Original line Diff line number Diff line Loading @@ -55,6 +55,16 @@ class Declaration; } } } } /* * nsCSSCompressedDataBlock holds property-value pairs corresponding * to CSS declaration blocks. Each pair is stored in a CDBValueStorage * object; these objects form an array at the end of the data block. */ struct CDBValueStorage { nsCSSProperty property; nsCSSValue value; }; /** /** * An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of * An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of * property-value data for a CSS declaration block (which we misname a * property-value data for a CSS declaration block (which we misname a Loading @@ -67,9 +77,7 @@ private: // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock // (in |Compress|) can create compressed data blocks. // (in |Compress|) can create compressed data blocks. nsCSSCompressedDataBlock(PRUint32 aNumProps) nsCSSCompressedDataBlock() : mStyleBits(0) {} : mStyleBits(0), mNumProps(aNumProps) {} public: public: ~nsCSSCompressedDataBlock(); ~nsCSSCompressedDataBlock(); Loading Loading @@ -116,88 +124,47 @@ public: size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const; size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const; private: private: void* operator new(size_t aBaseSize, PRUint32 aNumProps) { void* operator new(size_t aBaseSize, size_t aDataSize) { NS_ABORT_IF_FALSE(aBaseSize == sizeof(nsCSSCompressedDataBlock), NS_ABORT_IF_FALSE(aBaseSize == sizeof(nsCSSCompressedDataBlock), "unexpected size for nsCSSCompressedDataBlock"); "unexpected size for nsCSSCompressedDataBlock"); return ::operator new(aBaseSize + DataSize(aNumProps)); return ::operator new(aBaseSize + aDataSize); } } public: /** // Ideally, |nsCSSProperty| would be |enum nsCSSProperty : PRInt16|. But * Delete all the data stored in this block, and the block itself. // not all of the compilers we use are modern enough to support small */ // enums. So we manually squeeze nsCSSProperty into 16 bits ourselves. void Destroy(); // The static assertion below ensures it fits. typedef PRInt16 CompressedCSSProperty; static const size_t MaxCompressedCSSProperty = PR_INT16_MAX; private: static size_t DataSize(PRUint32 aNumProps) { return size_t(aNumProps) * (sizeof(nsCSSValue) + sizeof(CompressedCSSProperty)); } PRInt32 mStyleBits; // the structs for which we have data, according to PRInt32 mStyleBits; // the structs for which we have data, according to // |nsCachedStyleData::GetBitForSID|. // |nsCachedStyleData::GetBitForSID|. PRUint32 mNumProps; PRUint32 mDataSize; // nsCSSValue elements are stored after these fields, and // CDBValueStorage elements are stored after these fields. Space for them // nsCSSProperty 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 // is allocated in |operator new| above. The static assertions following // this class make sure that the value and property elements are aligned // this class make sure that the CDBValueStorage elements are aligned // appropriately. // appropriately. nsCSSValue* Values() const { char* Block() { return (char*)this + sizeof(*this); } return (nsCSSValue*)(this + 1); char* BlockEnd() { return Block() + mDataSize; } } const char* Block() const { return (char*)this + sizeof(*this); } const char* BlockEnd() const { return Block() + mDataSize; } CompressedCSSProperty* CompressedProperties() const { void SetBlockEnd(char *blockEnd) { return (CompressedCSSProperty*)(Values() + mNumProps); /* } * Note: if we ever change nsCSSDeclaration to store the declarations * in order and also store repeated declarations of the same property, nsCSSValue* ValueAtIndex(PRUint32 i) const { * then we need to worry about checking for integer overflow here. NS_ABORT_IF_FALSE(i < mNumProps, "value index out of range"); */ return Values() + i; NS_ABORT_IF_FALSE(size_t(blockEnd - Block()) <= size_t(PR_UINT32_MAX), } "overflow of mDataSize"); mDataSize = PRUint32(blockEnd - Block()); nsCSSProperty PropertyAtIndex(PRUint32 i) const { NS_ABORT_IF_FALSE(i < mNumProps, "property index out of range"); nsCSSProperty prop = (nsCSSProperty)CompressedProperties()[i]; NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(prop), "out of range"); return prop; } void CopyValueToIndex(PRUint32 i, nsCSSValue* aValue) { new (ValueAtIndex(i)) nsCSSValue(*aValue); } void RawCopyValueToIndex(PRUint32 i, nsCSSValue* aValue) { memcpy(ValueAtIndex(i), aValue, sizeof(nsCSSValue)); } void SetPropertyAtIndex(PRUint32 i, nsCSSProperty aProperty) { NS_ABORT_IF_FALSE(i < mNumProps, "set property index out of range"); CompressedProperties()[i] = (CompressedCSSProperty)aProperty; } void SetNumPropsToZero() { mNumProps = 0; } } ptrdiff_t DataSize() const { return mDataSize; } }; }; // Make sure the values and properties are aligned appropriately. (These /* Make sure the CDBValueStorage elements are aligned appropriately. */ // assertions are stronger than necessary to keep them simple.) MOZ_STATIC_ASSERT(sizeof(nsCSSCompressedDataBlock) == 8, MOZ_STATIC_ASSERT(sizeof(nsCSSCompressedDataBlock) == 8, "nsCSSCompressedDataBlock's size has changed"); "nsCSSCompressedDataBlock's size has changed"); MOZ_STATIC_ASSERT(NS_ALIGNMENT_OF(nsCSSValue) == 4 || MOZ_STATIC_ASSERT(NS_ALIGNMENT_OF(CDBValueStorage) <= 8, NS_ALIGNMENT_OF(nsCSSValue) == 8, "CDBValueStorage needs too much alignment"); "nsCSSValue doesn't align with nsCSSCompressedDataBlock"); MOZ_STATIC_ASSERT(NS_ALIGNMENT_OF(nsCSSCompressedDataBlock::CompressedCSSProperty) == 2, "CompressedCSSProperty doesn't align with nsCSSValue"); // Make sure that sizeof(CompressedCSSProperty) is big enough. MOZ_STATIC_ASSERT(eCSSProperty_COUNT_no_shorthands <= nsCSSCompressedDataBlock::MaxCompressedCSSProperty, "nsCSSProperty doesn't fit in StoredSizeOfCSSProperty"); class nsCSSExpandedDataBlock { class nsCSSExpandedDataBlock { friend class nsCSSCompressedDataBlock; friend class nsCSSCompressedDataBlock; Loading Loading @@ -284,11 +251,13 @@ public: private: private: /** /** * Compute the number of properties that will be present in the * Compute the size that will be occupied by the result of * result of |Compress|. * |Compress|. */ */ void ComputeNumProps(PRUint32* aNumPropsNormal, struct ComputeSizeResult { PRUint32* aNumPropsImportant); PRUint32 normal, important; }; ComputeSizeResult ComputeSize(); void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant); void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant); Loading Loading
layout/style/nsCSSDataBlock.cpp +120 −46 Original line number Original line Diff line number Diff line Loading @@ -48,6 +48,34 @@ namespace css = mozilla::css; namespace css = mozilla::css; enum { CDBValueStorage_advance = sizeof(CDBValueStorage) }; /* * Define a bunch of utility functions for getting the property or any * of the value types when the cursor is at the beginning of the storage * for the property-value pair. The versions taking a non-const cursor * argument return a reference so that the caller can assign into the * result. */ inline nsCSSProperty& PropertyAtCursor(char *aCursor) { return *reinterpret_cast<nsCSSProperty*>(aCursor); } inline nsCSSProperty PropertyAtCursor(const char *aCursor) { return *reinterpret_cast<const nsCSSProperty*>(aCursor); } inline nsCSSValue* ValueAtCursor(char *aCursor) { return & reinterpret_cast<CDBValueStorage*>(aCursor)->value; } inline const nsCSSValue* ValueAtCursor(const char *aCursor) { return & reinterpret_cast<const CDBValueStorage*>(aCursor)->value; } /** /** * Does a fast move of aSource to aDest. The previous value in * Does a fast move of aSource to aDest. The previous value in * aDest is cleanly destroyed, and aSource is cleared. Returns * aDest is cleanly destroyed, and aSource is cleared. Returns Loading Loading @@ -136,13 +164,16 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const nsIDocument* doc = aRuleData->mPresContext->Document(); nsIDocument* doc = aRuleData->mPresContext->Document(); for (PRUint32 i = 0; i < mNumProps; i++) { const char* cursor = Block(); nsCSSProperty iProp = PropertyAtIndex(i); const char* cursor_end = BlockEnd(); while (cursor < cursor_end) { nsCSSProperty iProp = PropertyAtCursor(cursor); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) & if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) & aRuleData->mSIDs) { aRuleData->mSIDs) { nsCSSValue* target = aRuleData->ValueFor(iProp); nsCSSValue* target = aRuleData->ValueFor(iProp); if (target->GetUnit() == eCSSUnit_Null) { if (target->GetUnit() == eCSSUnit_Null) { const nsCSSValue *val = ValueAtIndex(i); const nsCSSValue *val = ValueAtCursor(cursor); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); if (ShouldStartImageLoads(aRuleData, iProp)) { if (ShouldStartImageLoads(aRuleData, iProp)) { TryToStartImageLoad(*val, doc, iProp); TryToStartImageLoad(*val, doc, iProp); Loading @@ -166,7 +197,9 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const } } } } } } cursor += CDBValueStorage_advance; } } NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data"); } } const nsCSSValue* const nsCSSValue* Loading @@ -183,11 +216,17 @@ nsCSSCompressedDataBlock::ValueFor(nsCSSProperty aProperty) const mStyleBits)) mStyleBits)) return nsnull; return nsnull; for (PRUint32 i = 0; i < mNumProps; i++) { const char* cursor = Block(); if (PropertyAtIndex(i) == aProperty) { const char* cursor_end = BlockEnd(); return ValueAtIndex(i); while (cursor < cursor_end) { nsCSSProperty iProp = PropertyAtCursor(cursor); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); if (iProp == aProperty) { return ValueAtCursor(cursor); } } cursor += CDBValueStorage_advance; } } NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data"); return nsnull; return nsnull; } } Loading Loading @@ -215,35 +254,56 @@ nsCSSCompressedDataBlock::TryReplaceValue(nsCSSProperty aProperty, nsCSSCompressedDataBlock* nsCSSCompressedDataBlock* nsCSSCompressedDataBlock::Clone() const nsCSSCompressedDataBlock::Clone() const { { nsAutoPtr<nsCSSCompressedDataBlock> const char *cursor = Block(), *cursor_end = BlockEnd(); result(new(mNumProps) nsCSSCompressedDataBlock(mNumProps)); char *result_cursor; result->mStyleBits = mStyleBits; nsAutoPtr<nsCSSCompressedDataBlock> result (new(cursor_end - cursor) nsCSSCompressedDataBlock()); if (!result) return nsnull; result_cursor = result->Block(); for (PRUint32 i = 0; i < mNumProps; i++) { while (cursor < cursor_end) { result->SetPropertyAtIndex(i, PropertyAtIndex(i)); nsCSSProperty iProp = PropertyAtCursor(cursor); result->CopyValueToIndex(i, ValueAtIndex(i)); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); PropertyAtCursor(result_cursor) = iProp; const nsCSSValue* val = ValueAtCursor(cursor); nsCSSValue *result_val = ValueAtCursor(result_cursor); new (result_val) nsCSSValue(*val); cursor += CDBValueStorage_advance; result_cursor += CDBValueStorage_advance; } } NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data"); result->SetBlockEnd(result_cursor); result->mStyleBits = mStyleBits; NS_ABORT_IF_FALSE(result->DataSize() == DataSize(), "wrong size"); return result.forget(); return result.forget(); } } nsCSSCompressedDataBlock::~nsCSSCompressedDataBlock() nsCSSCompressedDataBlock::~nsCSSCompressedDataBlock() { { for (PRUint32 i = 0; i < mNumProps; i++) { const char* cursor = Block(); #ifdef DEBUG const char* cursor_end = BlockEnd(); (void)PropertyAtIndex(i); // this checks the property is in range while (cursor < cursor_end) { #endif NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(PropertyAtCursor(cursor)), const nsCSSValue* val = ValueAtIndex(i); "out of range"); const nsCSSValue* val = ValueAtCursor(cursor); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); val->~nsCSSValue(); val->~nsCSSValue(); cursor += CDBValueStorage_advance; } } NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data"); } } /* static */ nsCSSCompressedDataBlock* /* static */ nsCSSCompressedDataBlock* nsCSSCompressedDataBlock::CreateEmptyBlock() nsCSSCompressedDataBlock::CreateEmptyBlock() { { nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock(0); nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock(); result->SetBlockEnd(result->Block()); return result; return result; } } Loading @@ -251,8 +311,12 @@ size_t nsCSSCompressedDataBlock::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const nsCSSCompressedDataBlock::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const { { size_t n = aMallocSizeOf(this); size_t n = aMallocSizeOf(this); for (PRUint32 i = 0; i < mNumProps; i++) { n += ValueAtIndex(i)->SizeOfExcludingThis(aMallocSizeOf); const char* cursor = Block(); const char* cursor_end = BlockEnd(); while (cursor < cursor_end) { n += ValueAtCursor(cursor)->SizeOfExcludingThis(aMallocSizeOf); cursor += CDBValueStorage_advance; } } return n; return n; } } Loading @@ -277,8 +341,10 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock, * Save needless copying and allocation by copying the memory * Save needless copying and allocation by copying the memory * corresponding to the stored data in the compressed block. * corresponding to the stored data in the compressed block. */ */ for (PRUint32 i = 0; i < aBlock->mNumProps; i++) { const char* cursor = aBlock->Block(); nsCSSProperty iProp = aBlock->PropertyAtIndex(i); const char* cursor_end = aBlock->BlockEnd(); while (cursor < cursor_end) { nsCSSProperty iProp = PropertyAtCursor(cursor); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); NS_ABORT_IF_FALSE(!HasPropertyBit(iProp), NS_ABORT_IF_FALSE(!HasPropertyBit(iProp), "compressed block has property multiple times"); "compressed block has property multiple times"); Loading @@ -286,7 +352,7 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock, if (aImportant) if (aImportant) SetImportantBit(iProp); SetImportantBit(iProp); const nsCSSValue* val = aBlock->ValueAtIndex(i); const nsCSSValue* val = ValueAtCursor(cursor); nsCSSValue* dest = PropertyAt(iProp); nsCSSValue* dest = PropertyAt(iProp); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); NS_ABORT_IF_FALSE(dest->GetUnit() == eCSSUnit_Null, NS_ABORT_IF_FALSE(dest->GetUnit() == eCSSUnit_Null, Loading @@ -295,11 +361,12 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock, dest->~nsCSSValue(); dest->~nsCSSValue(); #endif #endif memcpy(dest, val, sizeof(nsCSSValue)); memcpy(dest, val, sizeof(nsCSSValue)); cursor += CDBValueStorage_advance; } } NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data"); // Set the number of properties to zero so that we don't destroy the // Don't destroy remnants of what we just copied // remnants of what we just copied. aBlock->SetBlockEnd(aBlock->Block()); aBlock->SetNumPropsToZero(); delete aBlock; delete aBlock; } } Loading @@ -316,11 +383,10 @@ nsCSSExpandedDataBlock::Expand(nsCSSCompressedDataBlock *aNormalBlock, } } } } void nsCSSExpandedDataBlock::ComputeSizeResult nsCSSExpandedDataBlock::ComputeNumProps(PRUint32* aNumPropsNormal, nsCSSExpandedDataBlock::ComputeSize() PRUint32* aNumPropsImportant) { { *aNumPropsNormal = *aNumPropsImportant = 0; ComputeSizeResult result = {0, 0}; for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) { for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) { if (!mPropertiesSet.HasPropertyInChunk(iHigh)) if (!mPropertiesSet.HasPropertyInChunk(iHigh)) continue; continue; Loading @@ -334,11 +400,12 @@ nsCSSExpandedDataBlock::ComputeNumProps(PRUint32* aNumPropsNormal, NS_ABORT_IF_FALSE(PropertyAt(iProp)->GetUnit() != eCSSUnit_Null, NS_ABORT_IF_FALSE(PropertyAt(iProp)->GetUnit() != eCSSUnit_Null, "null value while computing size"); "null value while computing size"); if (mPropertiesImportant.HasPropertyAt(iHigh, iLow)) if (mPropertiesImportant.HasPropertyAt(iHigh, iLow)) (*aNumPropsImportant)++; result.important += CDBValueStorage_advance; else else (*aNumPropsNormal)++; result.normal += CDBValueStorage_advance; } } } } return result; } } void void Loading @@ -346,19 +413,19 @@ nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock, nsCSSCompressedDataBlock **aImportantBlock) nsCSSCompressedDataBlock **aImportantBlock) { { nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important; nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important; PRUint32 i_normal = 0, i_important = 0; char *cursor_normal, *cursor_important; PRUint32 numPropsNormal, numPropsImportant; ComputeSizeResult size = ComputeSize(); ComputeNumProps(&numPropsNormal, &numPropsImportant); result_normal = result_normal = new(size.normal) nsCSSCompressedDataBlock(); new(numPropsNormal) nsCSSCompressedDataBlock(numPropsNormal); cursor_normal = result_normal->Block(); if (numPropsImportant != 0) { if (size.important != 0) { result_important = result_important = new(size.important) nsCSSCompressedDataBlock(); new(numPropsImportant) nsCSSCompressedDataBlock(numPropsImportant); cursor_important = result_important->Block(); } else { } else { result_important = nsnull; result_important = nsnull; cursor_important = nsnull; } } /* /* Loading @@ -376,25 +443,32 @@ nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock, NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); bool important = bool important = mPropertiesImportant.HasPropertyAt(iHigh, iLow); mPropertiesImportant.HasPropertyAt(iHigh, iLow); char *&cursor = important ? cursor_important : cursor_normal; nsCSSCompressedDataBlock *result = nsCSSCompressedDataBlock *result = important ? result_important : result_normal; important ? result_important : result_normal; PRUint32* ip = important ? &i_important : &i_normal; nsCSSValue* val = PropertyAt(iProp); nsCSSValue* val = PropertyAt(iProp); NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "Null value while compressing"); "Null value while compressing"); result->SetPropertyAtIndex(*ip, iProp); CDBValueStorage *storage = result->RawCopyValueToIndex(*ip, val); reinterpret_cast<CDBValueStorage*>(cursor); storage->property = iProp; memcpy(&storage->value, val, sizeof(nsCSSValue)); new (val) nsCSSValue(); new (val) nsCSSValue(); (*ip)++; cursor += CDBValueStorage_advance; result->mStyleBits |= result->mStyleBits |= nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]); nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]); } } } } NS_ABORT_IF_FALSE(numPropsNormal == i_normal, "bad numProps"); result_normal->SetBlockEnd(cursor_normal); NS_ABORT_IF_FALSE(result_normal->DataSize() == ptrdiff_t(size.normal), "size miscalculation"); if (result_important) { if (result_important) { NS_ABORT_IF_FALSE(numPropsImportant == i_important, "bad numProps"); result_important->SetBlockEnd(cursor_important); NS_ABORT_IF_FALSE(result_important->DataSize() == ptrdiff_t(size.important), "size miscalculation"); } } ClearSets(); ClearSets(); Loading
layout/style/nsCSSDataBlock.h +45 −76 Original line number Original line Diff line number Diff line Loading @@ -55,6 +55,16 @@ class Declaration; } } } } /* * nsCSSCompressedDataBlock holds property-value pairs corresponding * to CSS declaration blocks. Each pair is stored in a CDBValueStorage * object; these objects form an array at the end of the data block. */ struct CDBValueStorage { nsCSSProperty property; nsCSSValue value; }; /** /** * An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of * An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of * property-value data for a CSS declaration block (which we misname a * property-value data for a CSS declaration block (which we misname a Loading @@ -67,9 +77,7 @@ private: // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock // Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock // (in |Compress|) can create compressed data blocks. // (in |Compress|) can create compressed data blocks. nsCSSCompressedDataBlock(PRUint32 aNumProps) nsCSSCompressedDataBlock() : mStyleBits(0) {} : mStyleBits(0), mNumProps(aNumProps) {} public: public: ~nsCSSCompressedDataBlock(); ~nsCSSCompressedDataBlock(); Loading Loading @@ -116,88 +124,47 @@ public: size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const; size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const; private: private: void* operator new(size_t aBaseSize, PRUint32 aNumProps) { void* operator new(size_t aBaseSize, size_t aDataSize) { NS_ABORT_IF_FALSE(aBaseSize == sizeof(nsCSSCompressedDataBlock), NS_ABORT_IF_FALSE(aBaseSize == sizeof(nsCSSCompressedDataBlock), "unexpected size for nsCSSCompressedDataBlock"); "unexpected size for nsCSSCompressedDataBlock"); return ::operator new(aBaseSize + DataSize(aNumProps)); return ::operator new(aBaseSize + aDataSize); } } public: /** // Ideally, |nsCSSProperty| would be |enum nsCSSProperty : PRInt16|. But * Delete all the data stored in this block, and the block itself. // not all of the compilers we use are modern enough to support small */ // enums. So we manually squeeze nsCSSProperty into 16 bits ourselves. void Destroy(); // The static assertion below ensures it fits. typedef PRInt16 CompressedCSSProperty; static const size_t MaxCompressedCSSProperty = PR_INT16_MAX; private: static size_t DataSize(PRUint32 aNumProps) { return size_t(aNumProps) * (sizeof(nsCSSValue) + sizeof(CompressedCSSProperty)); } PRInt32 mStyleBits; // the structs for which we have data, according to PRInt32 mStyleBits; // the structs for which we have data, according to // |nsCachedStyleData::GetBitForSID|. // |nsCachedStyleData::GetBitForSID|. PRUint32 mNumProps; PRUint32 mDataSize; // nsCSSValue elements are stored after these fields, and // CDBValueStorage elements are stored after these fields. Space for them // nsCSSProperty 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 // is allocated in |operator new| above. The static assertions following // this class make sure that the value and property elements are aligned // this class make sure that the CDBValueStorage elements are aligned // appropriately. // appropriately. nsCSSValue* Values() const { char* Block() { return (char*)this + sizeof(*this); } return (nsCSSValue*)(this + 1); char* BlockEnd() { return Block() + mDataSize; } } const char* Block() const { return (char*)this + sizeof(*this); } const char* BlockEnd() const { return Block() + mDataSize; } CompressedCSSProperty* CompressedProperties() const { void SetBlockEnd(char *blockEnd) { return (CompressedCSSProperty*)(Values() + mNumProps); /* } * Note: if we ever change nsCSSDeclaration to store the declarations * in order and also store repeated declarations of the same property, nsCSSValue* ValueAtIndex(PRUint32 i) const { * then we need to worry about checking for integer overflow here. NS_ABORT_IF_FALSE(i < mNumProps, "value index out of range"); */ return Values() + i; NS_ABORT_IF_FALSE(size_t(blockEnd - Block()) <= size_t(PR_UINT32_MAX), } "overflow of mDataSize"); mDataSize = PRUint32(blockEnd - Block()); nsCSSProperty PropertyAtIndex(PRUint32 i) const { NS_ABORT_IF_FALSE(i < mNumProps, "property index out of range"); nsCSSProperty prop = (nsCSSProperty)CompressedProperties()[i]; NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(prop), "out of range"); return prop; } void CopyValueToIndex(PRUint32 i, nsCSSValue* aValue) { new (ValueAtIndex(i)) nsCSSValue(*aValue); } void RawCopyValueToIndex(PRUint32 i, nsCSSValue* aValue) { memcpy(ValueAtIndex(i), aValue, sizeof(nsCSSValue)); } void SetPropertyAtIndex(PRUint32 i, nsCSSProperty aProperty) { NS_ABORT_IF_FALSE(i < mNumProps, "set property index out of range"); CompressedProperties()[i] = (CompressedCSSProperty)aProperty; } void SetNumPropsToZero() { mNumProps = 0; } } ptrdiff_t DataSize() const { return mDataSize; } }; }; // Make sure the values and properties are aligned appropriately. (These /* Make sure the CDBValueStorage elements are aligned appropriately. */ // assertions are stronger than necessary to keep them simple.) MOZ_STATIC_ASSERT(sizeof(nsCSSCompressedDataBlock) == 8, MOZ_STATIC_ASSERT(sizeof(nsCSSCompressedDataBlock) == 8, "nsCSSCompressedDataBlock's size has changed"); "nsCSSCompressedDataBlock's size has changed"); MOZ_STATIC_ASSERT(NS_ALIGNMENT_OF(nsCSSValue) == 4 || MOZ_STATIC_ASSERT(NS_ALIGNMENT_OF(CDBValueStorage) <= 8, NS_ALIGNMENT_OF(nsCSSValue) == 8, "CDBValueStorage needs too much alignment"); "nsCSSValue doesn't align with nsCSSCompressedDataBlock"); MOZ_STATIC_ASSERT(NS_ALIGNMENT_OF(nsCSSCompressedDataBlock::CompressedCSSProperty) == 2, "CompressedCSSProperty doesn't align with nsCSSValue"); // Make sure that sizeof(CompressedCSSProperty) is big enough. MOZ_STATIC_ASSERT(eCSSProperty_COUNT_no_shorthands <= nsCSSCompressedDataBlock::MaxCompressedCSSProperty, "nsCSSProperty doesn't fit in StoredSizeOfCSSProperty"); class nsCSSExpandedDataBlock { class nsCSSExpandedDataBlock { friend class nsCSSCompressedDataBlock; friend class nsCSSCompressedDataBlock; Loading Loading @@ -284,11 +251,13 @@ public: private: private: /** /** * Compute the number of properties that will be present in the * Compute the size that will be occupied by the result of * result of |Compress|. * |Compress|. */ */ void ComputeNumProps(PRUint32* aNumPropsNormal, struct ComputeSizeResult { PRUint32* aNumPropsImportant); PRUint32 normal, important; }; ComputeSizeResult ComputeSize(); void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant); void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant); Loading