mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Reference-count CSS compressed data blocks and make them immutable when their reference count is above 1. (Bug 522595) r=bzbarsky
This commit is contained in:
parent
ab7ecc4372
commit
9c2df8e0c0
@ -410,7 +410,7 @@ nsCSSCompressedDataBlock::StorageFor(nsCSSProperty aProperty) const
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsCSSCompressedDataBlock*
|
||||
already_AddRefed<nsCSSCompressedDataBlock>
|
||||
nsCSSCompressedDataBlock::Clone() const
|
||||
{
|
||||
const char *cursor = Block(), *cursor_end = BlockEnd();
|
||||
@ -489,6 +489,8 @@ nsCSSCompressedDataBlock::Clone() const
|
||||
result->mBlockEnd = result_cursor;
|
||||
result->mStyleBits = mStyleBits;
|
||||
NS_ASSERTION(result->DataSize() == DataSize(), "wrong size");
|
||||
|
||||
result->AddRef();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -544,13 +546,15 @@ nsCSSCompressedDataBlock::Destroy()
|
||||
delete this;
|
||||
}
|
||||
|
||||
/* static */ nsCSSCompressedDataBlock*
|
||||
/* static */ already_AddRefed<nsCSSCompressedDataBlock>
|
||||
nsCSSCompressedDataBlock::CreateEmptyBlock()
|
||||
{
|
||||
nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock();
|
||||
if (!result)
|
||||
return nsnull;
|
||||
result->mBlockEnd = result->Block();
|
||||
|
||||
result->AddRef();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -584,10 +588,22 @@ nsCSSExpandedDataBlock::kOffsetTable[eCSSProperty_COUNT_no_shorthands] = {
|
||||
};
|
||||
|
||||
void
|
||||
nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock,
|
||||
nsCSSExpandedDataBlock::DoExpand(nsRefPtr<nsCSSCompressedDataBlock> *aBlock,
|
||||
PRBool aImportant)
|
||||
{
|
||||
NS_PRECONDITION(aBlock, "unexpected null block");
|
||||
NS_PRECONDITION(*aBlock, "unexpected null block");
|
||||
|
||||
if (!(*aBlock)->IsMutable()) {
|
||||
// FIXME (maybe): We really don't need to clone the block
|
||||
// itself, just all the data inside it.
|
||||
*aBlock = (*aBlock)->Clone();
|
||||
if (!aBlock) {
|
||||
// Not much we can do; just lose the properties.
|
||||
NS_WARNING("out of memory");
|
||||
return;
|
||||
}
|
||||
NS_ABORT_IF_FALSE((*aBlock)->IsMutable(), "we just cloned it");
|
||||
}
|
||||
|
||||
/*
|
||||
* Save needless copying and allocation by copying the memory
|
||||
@ -595,8 +611,8 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock,
|
||||
* then, to avoid destructors, deleting the compressed block by
|
||||
* calling |delete| instead of using its |Destroy| method.
|
||||
*/
|
||||
const char* cursor = aBlock->Block();
|
||||
const char* cursor_end = aBlock->BlockEnd();
|
||||
const char* cursor = (*aBlock)->Block();
|
||||
const char* cursor_end = (*aBlock)->BlockEnd();
|
||||
while (cursor < cursor_end) {
|
||||
nsCSSProperty iProp = PropertyAtCursor(cursor);
|
||||
NS_ASSERTION(0 <= iProp && iProp < eCSSProperty_COUNT_no_shorthands,
|
||||
@ -663,21 +679,21 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock,
|
||||
}
|
||||
NS_ASSERTION(cursor == cursor_end, "inconsistent data");
|
||||
|
||||
delete aBlock;
|
||||
NS_ASSERTION((*aBlock)->mRefCnt == 1, "unexpected reference count");
|
||||
delete aBlock->forget().get();
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSExpandedDataBlock::Expand(nsCSSCompressedDataBlock **aNormalBlock,
|
||||
nsCSSCompressedDataBlock **aImportantBlock)
|
||||
nsCSSExpandedDataBlock::Expand(
|
||||
nsRefPtr<nsCSSCompressedDataBlock> *aNormalBlock,
|
||||
nsRefPtr<nsCSSCompressedDataBlock> *aImportantBlock)
|
||||
{
|
||||
NS_PRECONDITION(*aNormalBlock, "unexpected null block");
|
||||
AssertInitialState();
|
||||
|
||||
DoExpand(*aNormalBlock, PR_FALSE);
|
||||
*aNormalBlock = nsnull;
|
||||
DoExpand(aNormalBlock, PR_FALSE);
|
||||
if (*aImportantBlock) {
|
||||
DoExpand(*aImportantBlock, PR_TRUE);
|
||||
*aImportantBlock = nsnull;
|
||||
DoExpand(aImportantBlock, PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,7 +765,7 @@ void
|
||||
nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock,
|
||||
nsCSSCompressedDataBlock **aImportantBlock)
|
||||
{
|
||||
nsCSSCompressedDataBlock *result_normal, *result_important;
|
||||
nsRefPtr<nsCSSCompressedDataBlock> result_normal, result_important;
|
||||
char *cursor_normal, *cursor_important;
|
||||
|
||||
ComputeSizeResult size = ComputeSize();
|
||||
@ -765,7 +781,6 @@ nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock,
|
||||
if (size.important != 0) {
|
||||
result_important = new(size.important) nsCSSCompressedDataBlock();
|
||||
if (!result_important) {
|
||||
delete result_normal;
|
||||
*aNormalBlock = nsnull;
|
||||
*aImportantBlock = nsnull;
|
||||
return;
|
||||
@ -861,8 +876,8 @@ nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock,
|
||||
|
||||
ClearSets();
|
||||
AssertInitialState();
|
||||
*aNormalBlock = result_normal;
|
||||
*aImportantBlock = result_important;
|
||||
result_normal.forget(aNormalBlock);
|
||||
result_important.forget(aImportantBlock);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "nsCSSStruct.h"
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsCSSPropertySet.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
struct nsRuleData;
|
||||
|
||||
@ -56,6 +57,11 @@ class nsCSSDeclaration;
|
||||
* property-value data for a CSS declaration block (which we misname a
|
||||
* |nsCSSDeclaration|). Mutation is accomplished through
|
||||
* |nsCSSExpandedDataBlock| or in some cases via direct slot access.
|
||||
*
|
||||
* Mutation is forbidden when the reference count is greater than one,
|
||||
* since once a style rule has used a compressed data block, mutation of
|
||||
* that block is forbidden, and any declarations that want to mutate it
|
||||
* need to clone it first.
|
||||
*/
|
||||
class nsCSSCompressedDataBlock {
|
||||
public:
|
||||
@ -119,21 +125,36 @@ public:
|
||||
/**
|
||||
* Clone this block, or return null on out-of-memory.
|
||||
*/
|
||||
nsCSSCompressedDataBlock* Clone() const;
|
||||
|
||||
/**
|
||||
* Delete all the data stored in this block, and the block itself.
|
||||
*/
|
||||
void Destroy();
|
||||
already_AddRefed<nsCSSCompressedDataBlock> Clone() const;
|
||||
|
||||
/**
|
||||
* Create a new nsCSSCompressedDataBlock holding no declarations.
|
||||
*/
|
||||
static nsCSSCompressedDataBlock* CreateEmptyBlock();
|
||||
static already_AddRefed<nsCSSCompressedDataBlock> CreateEmptyBlock();
|
||||
|
||||
void AddRef() {
|
||||
NS_ASSERTION(mRefCnt == 0 || mRefCnt == 1,
|
||||
"unexpected reference count");
|
||||
++mRefCnt;
|
||||
}
|
||||
void Release() {
|
||||
NS_ASSERTION(mRefCnt == 1 || mRefCnt == 2,
|
||||
"unexpected reference count");
|
||||
if (--mRefCnt == 0) {
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
PRBool IsMutable() const {
|
||||
NS_ASSERTION(mRefCnt == 1 || mRefCnt == 2,
|
||||
"unexpected reference count");
|
||||
return mRefCnt < 2;
|
||||
}
|
||||
|
||||
private:
|
||||
PRInt32 mStyleBits; // the structs for which we have data, according to
|
||||
// |nsCachedStyleData::GetBitForSID|.
|
||||
nsAutoRefCnt mRefCnt;
|
||||
|
||||
enum { block_chars = 4 }; // put 4 chars in the definition of the class
|
||||
// to ensure size not inflated by alignment
|
||||
@ -150,6 +171,11 @@ private:
|
||||
// |Expand|) can delete compressed data blocks.
|
||||
~nsCSSCompressedDataBlock() { }
|
||||
|
||||
/**
|
||||
* Delete all the data stored in this block, and the block itself.
|
||||
*/
|
||||
void Destroy();
|
||||
|
||||
char* mBlockEnd; // the byte after the last valid byte
|
||||
char mBlock_[block_chars]; // must be the last member!
|
||||
|
||||
@ -162,6 +188,7 @@ private:
|
||||
// Direct slot access to our values. See StorageFor above. Can
|
||||
// return null. Must not be called for shorthand properties.
|
||||
void* SlotForValue(nsCSSProperty aProperty) {
|
||||
NS_ABORT_IF_FALSE(IsMutable(), "must be mutable");
|
||||
return const_cast<void*>(StorageFor(aProperty));
|
||||
}
|
||||
};
|
||||
@ -199,13 +226,13 @@ public:
|
||||
* expanded block. The state of this expanded block must be clear
|
||||
* beforehand.
|
||||
*
|
||||
* The compressed block passed in IS DESTROYED by this method and
|
||||
* The compressed block passed in IS RELEASED by this method and
|
||||
* set to null, and thus cannot be used again. (This is necessary
|
||||
* because ownership of sub-objects is transferred to the expanded
|
||||
* block.)
|
||||
* block in many cases.)
|
||||
*/
|
||||
void Expand(nsCSSCompressedDataBlock **aNormalBlock,
|
||||
nsCSSCompressedDataBlock **aImportantBlock);
|
||||
void Expand(nsRefPtr<nsCSSCompressedDataBlock> *aNormalBlock,
|
||||
nsRefPtr<nsCSSCompressedDataBlock> *aImportantBlock);
|
||||
|
||||
/**
|
||||
* Allocate a new compressed block and transfer all of the state
|
||||
@ -242,7 +269,8 @@ private:
|
||||
};
|
||||
ComputeSizeResult ComputeSize();
|
||||
|
||||
void DoExpand(nsCSSCompressedDataBlock *aBlock, PRBool aImportant);
|
||||
void DoExpand(nsRefPtr<nsCSSCompressedDataBlock> *aBlock,
|
||||
PRBool aImportant);
|
||||
|
||||
#ifdef DEBUG
|
||||
void DoAssertInitialState();
|
||||
|
@ -62,8 +62,6 @@
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
nsCSSDeclaration::nsCSSDeclaration()
|
||||
: mData(nsnull),
|
||||
mImportantData(nsnull)
|
||||
{
|
||||
// check that we can fit all the CSS properties into a PRUint8
|
||||
// for the mOrder array - if not, might need to use PRUint16!
|
||||
@ -74,22 +72,17 @@ nsCSSDeclaration::nsCSSDeclaration()
|
||||
|
||||
nsCSSDeclaration::nsCSSDeclaration(const nsCSSDeclaration& aCopy)
|
||||
: mOrder(aCopy.mOrder),
|
||||
mData(aCopy.mData ? aCopy.mData->Clone() : nsnull),
|
||||
mImportantData(aCopy.mImportantData ? aCopy.mImportantData->Clone()
|
||||
: nsnull)
|
||||
mData(aCopy.mData ? aCopy.mData->Clone()
|
||||
: already_AddRefed<nsCSSCompressedDataBlock>(nsnull)),
|
||||
mImportantData(aCopy.mImportantData
|
||||
? aCopy.mImportantData->Clone()
|
||||
: already_AddRefed<nsCSSCompressedDataBlock>(nsnull))
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsCSSDeclaration);
|
||||
}
|
||||
|
||||
nsCSSDeclaration::~nsCSSDeclaration(void)
|
||||
{
|
||||
if (mData) {
|
||||
mData->Destroy();
|
||||
}
|
||||
if (mImportantData) {
|
||||
mImportantData->Destroy();
|
||||
}
|
||||
|
||||
MOZ_COUNT_DTOR(nsCSSDeclaration);
|
||||
}
|
||||
|
||||
@ -108,7 +101,7 @@ nsresult
|
||||
nsCSSDeclaration::RemoveProperty(nsCSSProperty aProperty)
|
||||
{
|
||||
nsCSSExpandedDataBlock data;
|
||||
data.Expand(&mData, &mImportantData);
|
||||
ExpandTo(&data);
|
||||
NS_ASSERTION(!mData && !mImportantData, "Expand didn't null things out");
|
||||
|
||||
if (nsCSSProps::IsShorthand(aProperty)) {
|
||||
@ -121,7 +114,7 @@ nsCSSDeclaration::RemoveProperty(nsCSSProperty aProperty)
|
||||
mOrder.RemoveElement(aProperty);
|
||||
}
|
||||
|
||||
data.Compress(&mData, &mImportantData);
|
||||
CompressFrom(&data);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,8 @@ public:
|
||||
void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) {
|
||||
NS_ASSERTION(!mData, "oops");
|
||||
NS_ASSERTION(!mImportantData, "oops");
|
||||
aExpandedData->Compress(&mData, &mImportantData);
|
||||
aExpandedData->Compress(getter_AddRefs(mData),
|
||||
getter_AddRefs(mImportantData));
|
||||
aExpandedData->AssertInitialState();
|
||||
}
|
||||
|
||||
@ -157,12 +158,8 @@ public:
|
||||
* new data by a call to |CompressFrom|.
|
||||
*/
|
||||
void ClearData() {
|
||||
mData->Destroy();
|
||||
mData = nsnull;
|
||||
if (mImportantData) {
|
||||
mImportantData->Destroy();
|
||||
mImportantData = nsnull;
|
||||
}
|
||||
mImportantData = nsnull;
|
||||
mOrder.Clear();
|
||||
}
|
||||
|
||||
@ -237,8 +234,12 @@ private:
|
||||
private:
|
||||
nsAutoTArray<PRUint8, 8> mOrder;
|
||||
nsAutoRefCnt mRefCnt;
|
||||
nsCSSCompressedDataBlock *mData; // never null, except while expanded
|
||||
nsCSSCompressedDataBlock *mImportantData; // may be null
|
||||
|
||||
// never null, except while expanded
|
||||
nsRefPtr<nsCSSCompressedDataBlock> mData;
|
||||
|
||||
// may be null
|
||||
nsRefPtr<nsCSSCompressedDataBlock> mImportantData;
|
||||
};
|
||||
|
||||
#endif /* nsCSSDeclaration_h___ */
|
||||
|
Loading…
Reference in New Issue
Block a user