Bug 1188721 - Part 5: Destroy structs replaced in GetUniqueStyleData. r?dbaron
MozReview-Commit-ID: Irf4KlgkHkM
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -48,16 +48,23 @@ public:
bool shouldDelete = mStyleStructs[aSID] &&
mStyleStructs[aSID]->ReleaseWithoutDestroying() == 0;
mStyleStructs[aSID] = nullptr;
return shouldDelete;
}
void SwapStyleData(nsStyleStructID aSID, nsInheritedStyleData& aOther) {
std::swap(mStyleStructs[aSID], aOther.mStyleStructs[aSID]);
}
+ bool ReplaceStyleData(nsStyleStructID aSID, nsStyleStruct* aStyleStruct) {
+ MOZ_ASSERT(aStyleStruct);
+ nsStyleStruct* old = mStyleStructs[aSID];
+ aStyleStruct->AddRef();
+ mStyleStructs[aSID] = aStyleStruct;
+ return old && old->ReleaseWithoutDestroying() == 0;
+ }
void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
return aContext->PresShell()->
AllocateByObjectID(mozilla::eArenaObjectID_nsInheritedStyleData, sz);
}
void DestroyStructs(nsPresContext* aContext) {
#define STYLE_STRUCT_INHERITED(name, checkdata_cb) \
@@ -111,16 +118,23 @@ public:
bool shouldDelete = mStyleStructs[aSID] &&
mStyleStructs[aSID]->ReleaseWithoutDestroying() == 0;
mStyleStructs[aSID] = nullptr;
return shouldDelete;
}
void SwapStyleData(nsStyleStructID aSID, nsResetStyleData& aOther) {
std::swap(mStyleStructs[aSID], aOther.mStyleStructs[aSID]);
}
+ bool ReplaceStyleData(nsStyleStructID aSID, nsStyleStruct* aStyleStruct) {
+ MOZ_ASSERT(aStyleStruct);
+ nsStyleStruct* old = mStyleStructs[aSID];
+ aStyleStruct->AddRef();
+ mStyleStructs[aSID] = aStyleStruct;
+ return old && old->ReleaseWithoutDestroying() == 0;
+ }
nsResetStyleData()
{
for (nsStyleStructID i = nsStyleStructID_Reset_Start;
i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
i = nsStyleStructID(i + 1)) {
mStyleStructs[i] = nullptr;
}
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -436,48 +436,62 @@ nsStyleContext::StyleData(nsStyleStructI
nsStyleStruct*
nsStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID)
{
// If we already own the struct and no kids could depend on it, then
// just return it. (We leak in this case if there are kids -- and this
// function really shouldn't be called for style contexts that could
// have kids depending on the data. ClearStyleData would be OK, but
// this test for no mChild or mEmptyChild doesn't catch that case.)
- const nsStyleStruct* current = StyleData(aSID);
+ auto current = const_cast<nsStyleStruct*>(StyleData(aSID));
if (!mChild && !mEmptyChild &&
!(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
GetCachedStyleData(aSID))
- return const_cast<nsStyleStruct*>(current);
+ return current;
- nsStyleStruct* result;
+ nsStyleStruct* newData;
nsPresContext *presContext = PresContext();
switch (aSID) {
#define UNIQUE_CASE(c_) \
- case eStyleStruct_##c_: \
- result = new (presContext) nsStyle##c_( \
- * static_cast<const nsStyle##c_ *>(current)); \
- break;
+ case eStyleStruct_##c_: { \
+ auto currentData = static_cast<nsStyle##c_*>(current); \
+ bool unreferenced; \
+ newData = new (presContext) nsStyle##c_(*currentData); \
+ if (nsCachedStyleData::IsReset(aSID)) { \
+ if (!mCachedResetData) { \
+ mCachedResetData = new (presContext) nsResetStyleData; \
+ } \
+ unreferenced = mCachedResetData->ReplaceStyleData(aSID, newData); \
+ } else { \
+ unreferenced = mCachedInheritedData.ReplaceStyleData(aSID, newData); \
+ } \
+ if (unreferenced) { \
+ /* if currentData, which ReplaceStyleData just released, went down */ \
+ /* to a zero refcount, we must destroy it */ \
+ currentData->Destroy(presContext); \
+ } \
+ break; \
+ }
UNIQUE_CASE(Display)
UNIQUE_CASE(Text)
UNIQUE_CASE(TextReset)
UNIQUE_CASE(Visibility)
#undef UNIQUE_CASE
default:
NS_ERROR("Struct type not supported. Please find another way to do this if you can!");
return nullptr;
}
- SetStyle(aSID, result);
mBits &= ~static_cast<uint64_t>(nsCachedStyleData::GetBitForSID(aSID));
- return result;
+ return newData;
}
// This is an evil function, but less evil than GetUniqueStyleData. It
// creates an empty style struct for this nsStyleContext.
nsStyleStruct*
nsStyleContext::CreateEmptyStyleData(const nsStyleStructID& aSID)
{
MOZ_ASSERT(!mChild && !mEmptyChild &&