Bug 773296 - Part 16: Add a ref-counted list nsCSSValue unit and use it for tranform lists; hold a strong reference to one on nsStyleDisplay. r=dbaron

This adds a new eCSSUnit_SharedList type for nsCSSValue, which is a
reference counted object that contains an nsCSSValueList.  We need this
so that nsStyleDisplay::mSpecifiedTransform can hold a strong reference
to a specified transform list value.  When 'transform' is specified
using a variable reference, the resulting nsCSSValue does not stick
around in the Declaration object, so we wouldn't be guaranteed that
it lives long enough for nsStyleDisplay to keep referencing it.
This commit is contained in:
Cameron McCormack
2013-12-12 13:09:44 +11:00
parent 615ac0aa43
commit 2d29cdbe6b
11 changed files with 165 additions and 26 deletions

View File

@@ -40,7 +40,7 @@
#endif
#include "GeckoProfiler.h"
struct nsCSSValueList;
struct nsCSSValueSharedList;
using namespace mozilla::dom;
@@ -348,7 +348,8 @@ SampleValue(float aPortion, Animation& aAnimation, nsStyleAnimation::Value& aSta
return;
}
nsCSSValueList* interpolatedList = interpolatedValue.GetCSSValueListValue();
nsCSSValueSharedList* interpolatedList =
interpolatedValue.GetCSSValueSharedListValue();
TransformData& data = aAnimation.data().get_TransformData();
nsPoint origin = data.origin();

View File

@@ -4059,7 +4059,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
frame && frame->IsSVGTransformed(&svgTransform, &transformFromSVGParent);
/* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
if (aProperties.mTransformList) {
result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList,
result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead,
frame ? frame->StyleContext() : nullptr,
frame ? frame->PresContext() : nullptr,
dummy, bounds, aAppUnitsPerPixel);

View File

@@ -3037,7 +3037,7 @@ public:
FrameTransformProperties(const nsIFrame* aFrame,
float aAppUnitsPerPixel,
const nsRect* aBoundsOverride);
FrameTransformProperties(const nsCSSValueList* aTransformList,
FrameTransformProperties(nsCSSValueSharedList* aTransformList,
const gfxPoint3D& aToTransformOrigin,
const gfxPoint3D& aToPerspectiveOrigin,
nscoord aChildPerspective)
@@ -3049,7 +3049,7 @@ public:
{}
const nsIFrame* mFrame;
const nsCSSValueList* mTransformList;
nsRefPtr<nsCSSValueSharedList> mTransformList;
const gfxPoint3D mToTransformOrigin;
const gfxPoint3D mToPerspectiveOrigin;
nscoord mChildPerspective;

View File

@@ -11179,7 +11179,10 @@ bool CSSParserImpl::ParseTransform(bool aIsPrefixed)
return false;
}
} else {
nsCSSValueList* cur = value.SetListValue();
nsCSSValueSharedList* list = new nsCSSValueSharedList;
value.SetSharedListValue(list);
list->mHead = new nsCSSValueList;
nsCSSValueList* cur = list->mHead;
for (;;) {
if (!ParseSingleTransform(aIsPrefixed, cur->mValue)) {
return false;

View File

@@ -162,6 +162,10 @@ nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
else if (eCSSUnit_ListDep == mUnit) {
mValue.mListDependent = aCopy.mValue.mListDependent;
}
else if (eCSSUnit_SharedList == mUnit) {
mValue.mSharedList = aCopy.mValue.mSharedList;
mValue.mSharedList->AddRef();
}
else if (eCSSUnit_PairList == mUnit) {
mValue.mPairList = aCopy.mValue.mPairList;
mValue.mPairList->AddRef();
@@ -232,6 +236,9 @@ bool nsCSSValue::operator==(const nsCSSValue& aOther) const
else if (eCSSUnit_List == mUnit) {
return *mValue.mList == *aOther.mValue.mList;
}
else if (eCSSUnit_SharedList == mUnit) {
return *mValue.mSharedList == *aOther.mValue.mSharedList;
}
else if (eCSSUnit_PairList == mUnit) {
return *mValue.mPairList == *aOther.mValue.mPairList;
}
@@ -315,6 +322,8 @@ void nsCSSValue::DoReset()
mValue.mRect->Release();
} else if (eCSSUnit_List == mUnit) {
mValue.mList->Release();
} else if (eCSSUnit_SharedList == mUnit) {
mValue.mSharedList->Release();
} else if (eCSSUnit_PairList == mUnit) {
mValue.mPairList->Release();
}
@@ -513,6 +522,14 @@ nsCSSValueList* nsCSSValue::SetListValue()
return mValue.mList;
}
void nsCSSValue::SetSharedListValue(nsCSSValueSharedList* aList)
{
Reset();
mUnit = eCSSUnit_SharedList;
mValue.mSharedList = aList;
mValue.mSharedList->AddRef();
}
void nsCSSValue::SetDependentListValue(nsCSSValueList* aList)
{
Reset();
@@ -1198,6 +1215,8 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult) const
GetRectValue().AppendToString(aProperty, aResult);
} else if (eCSSUnit_List == unit || eCSSUnit_ListDep == unit) {
GetListValue()->AppendToString(aProperty, aResult);
} else if (eCSSUnit_SharedList == unit) {
GetSharedListValue()->AppendToString(aProperty, aResult);
} else if (eCSSUnit_PairList == unit || eCSSUnit_PairListDep == unit) {
switch (aProperty) {
case eCSSProperty_font_feature_settings:
@@ -1258,6 +1277,7 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult) const
case eCSSUnit_Rect: break;
case eCSSUnit_List: break;
case eCSSUnit_ListDep: break;
case eCSSUnit_SharedList: break;
case eCSSUnit_PairList: break;
case eCSSUnit_PairListDep: break;
@@ -1384,6 +1404,12 @@ nsCSSValue::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
case eCSSUnit_ListDep:
break;
// SharedList
case eCSSUnit_SharedList:
// Makes more sense not to measure, since it most cases the list
// will be shared.
break;
// PairList
case eCSSUnit_PairList:
n += mValue.mPairList->SizeOfIncludingThis(aMallocSizeOf);
@@ -1522,6 +1548,41 @@ nsCSSValueList_heap::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) co
return n;
}
// --- nsCSSValueSharedList -----------------
nsCSSValueSharedList::~nsCSSValueSharedList()
{
MOZ_COUNT_DTOR(nsCSSValueSharedList);
if (mHead) {
NS_CSS_DELETE_LIST_MEMBER(nsCSSValueList, mHead, mNext);
delete mHead;
}
}
void
nsCSSValueSharedList::AppendToString(nsCSSProperty aProperty, nsAString& aResult) const
{
if (mHead) {
mHead->AppendToString(aProperty, aResult);
}
}
bool
nsCSSValueSharedList::operator==(const nsCSSValueSharedList& aOther) const
{
return !mHead == !aOther.mHead &&
(!mHead || *mHead == *aOther.mHead);
}
size_t
nsCSSValueSharedList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
size_t n = 0;
n += aMallocSizeOf(this);
n += mHead->SizeOfIncludingThis(aMallocSizeOf);
return n;
}
// --- nsCSSRect -----------------
nsCSSRect::nsCSSRect(void)

View File

@@ -197,8 +197,10 @@ enum nsCSSUnit {
eCSSUnit_List = 53, // (nsCSSValueList*) list of values
eCSSUnit_ListDep = 54, // (nsCSSValueList*) same as List
// but does not own the list
eCSSUnit_PairList = 55, // (nsCSSValuePairList*) list of value pairs
eCSSUnit_PairListDep = 56, // (nsCSSValuePairList*) same as PairList
eCSSUnit_SharedList = 55, // (nsCSSValueSharedList*) same as list
// but reference counted and shared
eCSSUnit_PairList = 56, // (nsCSSValuePairList*) list of value pairs
eCSSUnit_PairListDep = 57, // (nsCSSValuePairList*) same as PairList
// but does not own the list
eCSSUnit_Integer = 70, // (int) simple value
@@ -257,6 +259,7 @@ struct nsCSSRect;
struct nsCSSRect_heap;
struct nsCSSValueList;
struct nsCSSValueList_heap;
struct nsCSSValueSharedList;
struct nsCSSValuePairList;
struct nsCSSValuePairList_heap;
struct nsCSSValueTriplet;
@@ -430,6 +433,12 @@ public:
return mValue.mTokenStream;
}
nsCSSValueSharedList* GetSharedListValue() const
{
NS_ABORT_IF_FALSE(mUnit == eCSSUnit_SharedList, "not a shared list value");
return mValue.mSharedList;
}
// bodies of these are below
inline nsCSSValuePair& GetPairValue();
inline const nsCSSValuePair& GetPairValue() const;
@@ -498,6 +507,7 @@ public:
void SetTokenStreamValue(nsCSSValueTokenStream* aTokenStream);
void SetPairValue(const nsCSSValuePair* aPair);
void SetPairValue(const nsCSSValue& xValue, const nsCSSValue& yValue);
void SetSharedListValue(nsCSSValueSharedList* aList);
void SetDependentListValue(nsCSSValueList* aList);
void SetDependentPairListValue(nsCSSValuePairList* aList);
void SetTripletValue(const nsCSSValueTriplet* aTriplet);
@@ -557,6 +567,7 @@ protected:
nsCSSValueTriplet_heap* mTriplet;
nsCSSValueList_heap* mList;
nsCSSValueList* mListDependent;
nsCSSValueSharedList* mSharedList;
nsCSSValuePairList_heap* mPairList;
nsCSSValuePairList* mPairListDependent;
} mValue;
@@ -701,6 +712,38 @@ struct nsCSSValueList_heap : public nsCSSValueList {
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
};
// This is a reference counted list value. Note that the object is
// a wrapper for the reference count and a pointer to the head of the
// list, whereas the other list types (such as nsCSSValueList) do
// not have such a wrapper.
struct nsCSSValueSharedList {
nsCSSValueSharedList()
{
MOZ_COUNT_CTOR(nsCSSValueSharedList);
}
// Takes ownership of aList.
nsCSSValueSharedList(nsCSSValueList* aList)
: mHead(aList)
{
MOZ_COUNT_CTOR(nsCSSValueSharedList);
}
~nsCSSValueSharedList();
NS_INLINE_DECL_REFCOUNTING(nsCSSValueSharedList)
void AppendToString(nsCSSProperty aProperty, nsAString& aResult) const;
bool operator==(nsCSSValueSharedList const& aOther) const;
bool operator!=(const nsCSSValueSharedList& aOther) const
{ return !(*this == aOther); }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
nsCSSValueList* mHead;
};
// This has to be here so that the relationship between nsCSSValueList
// and nsCSSValueList_heap is visible.
inline nsCSSValueList*

View File

@@ -1232,7 +1232,7 @@ nsComputedDOMStyle::DoGetTransform()
bool dummy;
gfx3DMatrix matrix =
nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform,
nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform->mHead,
mStyleContextHolder,
mStyleContextHolder->PresContext(),
dummy,

View File

@@ -5354,15 +5354,16 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct,
canStoreInRuleTree = false;
break;
case eCSSUnit_List:
case eCSSUnit_ListDep: {
const nsCSSValueList* head = transformValue->GetListValue();
case eCSSUnit_SharedList: {
nsCSSValueSharedList* list = transformValue->GetSharedListValue();
nsCSSValueList* head = list->mHead;
MOZ_ASSERT(head, "transform list must have at least one item");
// can get a _None in here from transform animation
if (head->mValue.GetUnit() == eCSSUnit_None) {
NS_ABORT_IF_FALSE(head->mNext == nullptr, "none must be alone");
display->mSpecifiedTransform = nullptr;
} else {
display->mSpecifiedTransform = head; // weak pointer, owned by rule
display->mSpecifiedTransform = list;
}
break;
}

View File

@@ -2277,8 +2277,11 @@ nsStyleAnimation::AddWeighted(nsCSSProperty aProperty,
}
case eUnit_Transform: {
const nsCSSValueList *list1 = aValue1.GetCSSValueListValue();
const nsCSSValueList *list2 = aValue2.GetCSSValueListValue();
const nsCSSValueList* list1 = aValue1.GetCSSValueSharedListValue()->mHead;
const nsCSSValueList* list2 = aValue2.GetCSSValueSharedListValue()->mHead;
MOZ_ASSERT(list1);
MOZ_ASSERT(list2);
// We want to avoid the matrix decomposition when we can, since
// avoiding it can produce better results both for compound
@@ -2332,8 +2335,7 @@ nsStyleAnimation::AddWeighted(nsCSSProperty aProperty,
}
}
aResultValue.SetAndAdoptCSSValueListValue(result.forget(),
eUnit_Transform);
aResultValue.SetTransformValue(new nsCSSValueSharedList(result.forget()));
return true;
}
case eUnit_BackgroundPosition: {
@@ -2649,11 +2651,14 @@ nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty,
case eUnit_Dasharray:
case eUnit_Shadow:
case eUnit_Filter:
case eUnit_Transform:
case eUnit_BackgroundPosition:
aSpecifiedValue.
SetDependentListValue(aComputedValue.GetCSSValueListValue());
break;
case eUnit_Transform:
aSpecifiedValue.
SetSharedListValue(aComputedValue.GetCSSValueSharedListValue());
break;
case eUnit_CSSValuePairList:
aSpecifiedValue.
SetDependentPairListValue(aComputedValue.GetCSSValuePairListValue());
@@ -3308,7 +3313,7 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty,
if (display->mSpecifiedTransform) {
// Clone, and convert all lengths (not percents) to pixels.
nsCSSValueList **resultTail = getter_Transfers(result);
for (const nsCSSValueList *l = display->mSpecifiedTransform;
for (const nsCSSValueList *l = display->mSpecifiedTransform->mHead;
l; l = l->mNext) {
nsCSSValueList *clone = new nsCSSValueList;
*resultTail = clone;
@@ -3321,8 +3326,8 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty,
result->mValue.SetNoneValue();
}
aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
eUnit_Transform);
aComputedValue.SetTransformValue(
new nsCSSValueSharedList(result.forget()));
break;
}
@@ -3568,7 +3573,6 @@ nsStyleAnimation::Value::operator=(const Value& aOther)
case eUnit_Filter:
case eUnit_Dasharray:
case eUnit_Shadow:
case eUnit_Transform:
case eUnit_BackgroundPosition:
NS_ABORT_IF_FALSE(mUnit == eUnit_Shadow || mUnit == eUnit_Filter ||
aOther.mValue.mCSSValueList,
@@ -3582,6 +3586,10 @@ nsStyleAnimation::Value::operator=(const Value& aOther)
mValue.mCSSValueList = nullptr;
}
break;
case eUnit_Transform:
mValue.mCSSValueSharedList = aOther.mValue.mCSSValueSharedList;
mValue.mCSSValueSharedList->AddRef();
break;
case eUnit_CSSValuePairList:
NS_ABORT_IF_FALSE(aOther.mValue.mCSSValuePairList,
"value pair lists may not be null");
@@ -3728,6 +3736,15 @@ nsStyleAnimation::Value::SetAndAdoptCSSValueListValue(
mValue.mCSSValueList = aValueList; // take ownership
}
void
nsStyleAnimation::Value::SetTransformValue(nsCSSValueSharedList* aList)
{
FreeValue();
mUnit = eUnit_Transform;
mValue.mCSSValueSharedList = aList;
mValue.mCSSValueSharedList->AddRef();
}
void
nsStyleAnimation::Value::SetAndAdoptCSSValuePairListValue(
nsCSSValuePairList *aValuePairList)
@@ -3745,6 +3762,8 @@ nsStyleAnimation::Value::FreeValue()
delete mValue.mCSSValue;
} else if (IsCSSValueListUnit(mUnit)) {
delete mValue.mCSSValueList;
} else if (IsCSSValueSharedListValue(mUnit)) {
mValue.mCSSValueSharedList->Release();
} else if (IsCSSValuePairUnit(mUnit)) {
delete mValue.mCSSValuePair;
} else if (IsCSSValueTripletUnit(mUnit)) {
@@ -3794,9 +3813,10 @@ nsStyleAnimation::Value::operator==(const Value& aOther) const
case eUnit_Dasharray:
case eUnit_Filter:
case eUnit_Shadow:
case eUnit_Transform:
case eUnit_BackgroundPosition:
return *mValue.mCSSValueList == *aOther.mValue.mCSSValueList;
case eUnit_Transform:
return *mValue.mCSSValueSharedList == *aOther.mValue.mCSSValueSharedList;
case eUnit_CSSValuePairList:
return *mValue.mCSSValuePairList == *aOther.mValue.mCSSValuePairList;
case eUnit_UnparsedString:

View File

@@ -242,6 +242,7 @@ public:
nsCSSValueTriplet* mCSSValueTriplet;
nsCSSRect* mCSSRect;
nsCSSValueList* mCSSValueList;
nsCSSValueSharedList* mCSSValueSharedList;
nsCSSValuePairList* mCSSValuePairList;
nsStringBuffer* mString;
} mValue;
@@ -297,6 +298,10 @@ public:
NS_ASSERTION(IsCSSValueListUnit(mUnit), "unit mismatch");
return mValue.mCSSValueList;
}
nsCSSValueSharedList* GetCSSValueSharedListValue() const {
NS_ASSERTION(IsCSSValueSharedListValue(mUnit), "unit mismatch");
return mValue.mCSSValueSharedList;
}
nsCSSValuePairList* GetCSSValuePairListValue() const {
NS_ASSERTION(IsCSSValuePairListUnit(mUnit), "unit mismatch");
return mValue.mCSSValuePairList;
@@ -351,6 +356,8 @@ public:
void SetAndAdoptCSSValueListValue(nsCSSValueList *aValue, Unit aUnit);
void SetAndAdoptCSSValuePairListValue(nsCSSValuePairList *aValue);
void SetTransformValue(nsCSSValueSharedList* aList);
Value& operator=(const Value& aOther);
bool operator==(const Value& aOther) const;
@@ -382,9 +389,12 @@ public:
}
static bool IsCSSValueListUnit(Unit aUnit) {
return aUnit == eUnit_Dasharray || aUnit == eUnit_Filter ||
aUnit == eUnit_Shadow || aUnit == eUnit_Transform ||
aUnit == eUnit_Shadow ||
aUnit == eUnit_BackgroundPosition;
}
static bool IsCSSValueSharedListValue(Unit aUnit) {
return aUnit == eUnit_Transform;
}
static bool IsCSSValuePairListUnit(Unit aUnit) {
return aUnit == eUnit_CSSValuePairList;
}

View File

@@ -1724,10 +1724,10 @@ struct nsStyleDisplay {
// mSpecifiedTransform is the list of transform functions as
// specified, or null to indicate there is no transform. (inherit or
// initial are replaced by an actual list of transform functions, or
// null, as appropriate.) (owned by the style rule)
// null, as appropriate.)
uint8_t mBackfaceVisibility;
uint8_t mTransformStyle;
const nsCSSValueList *mSpecifiedTransform; // [reset]
nsRefPtr<nsCSSValueSharedList> mSpecifiedTransform; // [reset]
nsStyleCoord mTransformOrigin[3]; // [reset] percent, coord, calc, 3rd param is coord, calc only
nsStyleCoord mChildPerspective; // [reset] coord
nsStyleCoord mPerspectiveOrigin[2]; // [reset] percent, coord, calc