Bug 1026344 - Part 4: Make nsStyleCoord::Calc refcounted and introduce a non-refcounted nsStyleCoord::CalcValue. r=dbaron

This means that style structs holding computed calc() values are now able to be
stored in the rule tree.
This commit is contained in:
Cameron McCormack 2014-06-19 13:18:03 +10:00
parent 2d99ab3f74
commit b5d773f074
6 changed files with 208 additions and 65 deletions

View File

@ -1756,7 +1756,7 @@ nsComputedDOMStyle::DoGetBackgroundColor()
static void
SetValueToCalc(const nsStyleCoord::Calc *aCalc, nsROCSSPrimitiveValue *aValue)
SetValueToCalc(const nsStyleCoord::CalcValue *aCalc, nsROCSSPrimitiveValue *aValue)
{
nsRefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
nsAutoString tmp, result;

View File

@ -592,11 +592,7 @@ SpecifiedCalcToComputedCalc(const nsCSSValue& aValue, nsStyleCoord& aCoord,
aCanStoreInRuleTree);
nsRuleNode::ComputedCalc vals = ComputeCalc(aValue, ops);
nsStyleCoord::Calc *calcObj =
new (aStyleContext->Alloc(sizeof(nsStyleCoord::Calc))) nsStyleCoord::Calc;
// Because we use aStyleContext->Alloc(), we have to store the result
// on the style context and not in the rule tree.
aCanStoreInRuleTree = false;
nsStyleCoord::Calc* calcObj = new nsStyleCoord::Calc;
calcObj->mLength = vals.mLength;
calcObj->mPercent = vals.mPercent;
@ -622,7 +618,7 @@ nsRuleNode::SpecifiedCalcToComputedCalc(const nsCSSValue& aValue,
nsRuleNode::ComputeComputedCalc(const nsStyleCoord& aValue,
nscoord aPercentageBasis)
{
nsStyleCoord::Calc *calc = aValue.GetCalcValue();
nsStyleCoord::Calc* calc = aValue.GetCalcValue();
return calc->mLength +
NSToCoordFloorClamped(aPercentageBasis * calc->mPercent);
}

View File

@ -277,7 +277,8 @@ AppendCSSShadowValue(const nsCSSShadowItem *aShadow,
aResultTail = &resultItem->mNext;
}
// Like nsStyleCoord::Calc, but with length in float pixels instead of nscoord.
// Like nsStyleCoord::CalcValue, but with length in float pixels instead
// of nscoord.
struct PixelCalcValue {
float mLength, mPercent;
bool mHasPercent;
@ -357,7 +358,7 @@ ExtractCalcValue(const nsCSSValue& aValue)
}
static void
SetCalcValue(const nsStyleCoord::Calc* aCalc, nsCSSValue& aValue)
SetCalcValue(const nsStyleCoord::CalcValue* aCalc, nsCSSValue& aValue)
{
nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(1);
if (!aCalc->mHasPercent) {
@ -2791,7 +2792,7 @@ SubstitutePixelValues(nsStyleContext* aStyleContext,
nsRuleNode::SpecifiedCalcToComputedCalc(aInput, aStyleContext,
aStyleContext->PresContext(),
canStoreInRuleTree);
nsStyleCoord::Calc c2;
nsStyleCoord::CalcValue c2;
c2.mLength = c.mLength;
c2.mPercent = c.mPercent;
c2.mHasPercent = true; // doesn't matter for transform translate

View File

@ -7,6 +7,7 @@
#include "nsStyleCoord.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/PodOperations.h"
nsStyleCoord::nsStyleCoord(nsStyleUnit aUnit)
: mUnit(aUnit)
@ -40,7 +41,8 @@ nsStyleCoord::nsStyleCoord(float aValue, nsStyleUnit aUnit)
{
if (aUnit < eStyleUnit_Percent || aUnit >= eStyleUnit_Coord) {
NS_NOTREACHED("not a float value");
Reset();
mUnit = eStyleUnit_Null;
mValue.mInt = 0;
} else {
mValue.mFloat = aValue;
}
@ -112,12 +114,12 @@ uint32_t nsStyleCoord::HashValue(uint32_t aHash = 0) const
void nsStyleCoord::Reset()
{
mUnit = eStyleUnit_Null;
mValue.mInt = 0;
Reset(mUnit, mValue);
}
void nsStyleCoord::SetCoordValue(nscoord aValue)
{
Reset();
mUnit = eStyleUnit_Coord;
mValue.mInt = aValue;
}
@ -126,30 +128,31 @@ void nsStyleCoord::SetIntValue(int32_t aValue, nsStyleUnit aUnit)
{
NS_ASSERTION((aUnit == eStyleUnit_Enumerated) ||
(aUnit == eStyleUnit_Integer), "not an int value");
Reset();
if ((aUnit == eStyleUnit_Enumerated) ||
(aUnit == eStyleUnit_Integer)) {
mUnit = aUnit;
mValue.mInt = aValue;
}
else {
Reset();
}
}
void nsStyleCoord::SetPercentValue(float aValue)
{
Reset();
mUnit = eStyleUnit_Percent;
mValue.mFloat = aValue;
}
void nsStyleCoord::SetFactorValue(float aValue)
{
Reset();
mUnit = eStyleUnit_Factor;
mValue.mFloat = aValue;
}
void nsStyleCoord::SetAngleValue(float aValue, nsStyleUnit aUnit)
{
Reset();
if (aUnit == eStyleUnit_Degree ||
aUnit == eStyleUnit_Grad ||
aUnit == eStyleUnit_Radian ||
@ -158,36 +161,41 @@ void nsStyleCoord::SetAngleValue(float aValue, nsStyleUnit aUnit)
mValue.mFloat = aValue;
} else {
NS_NOTREACHED("not an angle value");
Reset();
}
}
void nsStyleCoord::SetFlexFractionValue(float aValue)
{
Reset();
mUnit = eStyleUnit_FlexFraction;
mValue.mFloat = aValue;
}
void nsStyleCoord::SetCalcValue(Calc* aValue)
{
Reset();
mUnit = eStyleUnit_Calc;
mValue.mPointer = aValue;
aValue->AddRef();
}
void nsStyleCoord::SetNormalValue()
{
Reset();
mUnit = eStyleUnit_Normal;
mValue.mInt = 0;
}
void nsStyleCoord::SetAutoValue()
{
Reset();
mUnit = eStyleUnit_Auto;
mValue.mInt = 0;
}
void nsStyleCoord::SetNoneValue()
{
Reset();
mUnit = eStyleUnit_None;
mValue.mInt = 0;
}
@ -213,7 +221,35 @@ nsStyleCoord::GetAngleValueInRadians() const
nsStyleSides::nsStyleSides()
{
memset(this, 0x00, sizeof(nsStyleSides));
NS_FOR_CSS_SIDES(i) {
mUnits[i] = eStyleUnit_Null;
}
mozilla::PodArrayZero(mValues);
}
nsStyleSides::nsStyleSides(const nsStyleSides& aOther)
{
NS_FOR_CSS_SIDES(i) {
mUnits[i] = eStyleUnit_Null;
}
*this = aOther;
}
nsStyleSides::~nsStyleSides()
{
Reset();
}
nsStyleSides&
nsStyleSides::operator=(const nsStyleSides& aCopy)
{
if (this != &aCopy) {
NS_FOR_CSS_SIDES(i) {
nsStyleCoord::SetValue(mUnits[i], mValues[i],
aCopy.mUnits[i], aCopy.mValues[i]);
}
}
return *this;
}
bool nsStyleSides::operator==(const nsStyleSides& aOther) const
@ -229,12 +265,42 @@ bool nsStyleSides::operator==(const nsStyleSides& aOther) const
void nsStyleSides::Reset()
{
memset(this, 0x00, sizeof(nsStyleSides));
NS_FOR_CSS_SIDES(i) {
nsStyleCoord::Reset(mUnits[i], mValues[i]);
}
}
nsStyleCorners::nsStyleCorners()
{
memset(this, 0x00, sizeof(nsStyleCorners));
NS_FOR_CSS_HALF_CORNERS(i) {
mUnits[i] = eStyleUnit_Null;
}
mozilla::PodArrayZero(mValues);
}
nsStyleCorners::nsStyleCorners(const nsStyleCorners& aOther)
{
NS_FOR_CSS_HALF_CORNERS(i) {
mUnits[i] = eStyleUnit_Null;
}
*this = aOther;
}
nsStyleCorners::~nsStyleCorners()
{
Reset();
}
nsStyleCorners&
nsStyleCorners::operator=(const nsStyleCorners& aCopy)
{
if (this != &aCopy) {
NS_FOR_CSS_HALF_CORNERS(i) {
nsStyleCoord::SetValue(mUnits[i], mValues[i],
aCopy.mUnits[i], aCopy.mValues[i]);
}
}
return *this;
}
bool
@ -251,7 +317,9 @@ nsStyleCorners::operator==(const nsStyleCorners& aOther) const
void nsStyleCorners::Reset()
{
memset(this, 0x00, sizeof(nsStyleCorners));
NS_FOR_CSS_HALF_CORNERS(i) {
nsStyleCoord::Reset(mUnits[i], mValues[i]);
}
}
// Validation of NS_SIDE_IS_VERTICAL and NS_HALF_CORNER_IS_X.

View File

@ -27,20 +27,18 @@ enum nsStyleUnit : uint8_t {
eStyleUnit_Integer = 30, // (int) value is simple integer
eStyleUnit_Enumerated = 32, // (int) value has enumerated meaning
// The following are allocated types. They are weak pointers to
// values allocated by nsStyleContext::Alloc.
eStyleUnit_Calc = 40 // (Calc*) calc() toplevel; always present
// The following are reference counted allocated types.
eStyleUnit_Calc = 40, // (Calc*) calc() toplevel; always present
// to distinguish 50% from calc(50%), etc.
eStyleUnit_MAX = 40 // highest valid nsStyleUnit value
};
typedef union {
int32_t mInt; // nscoord is a int32_t for now
float mFloat;
// An mPointer is a weak pointer to a value that is guaranteed to
// outlive the nsStyleCoord. In the case of nsStyleCoord::Calc*, it
// is a pointer owned by the style context, allocated through
// nsStyleContext::Alloc (and, therefore, is never stored in the rule
// tree).
// An mPointer is a reference counted pointer. Currently this can only
// ever be an nsStyleCoord::Calc*.
void* mPointer;
} nsStyleUnion;
@ -54,18 +52,34 @@ typedef union {
*/
class nsStyleCoord {
public:
struct Calc {
// Non-reference counted calc() value. See nsStyleStruct.h for some uses
// of this.
struct CalcValue {
// Every calc() expression evaluates to a length plus a percentage.
nscoord mLength;
float mPercent;
bool mHasPercent; // whether there was any % syntax, even if 0
bool operator==(const Calc& aOther) const {
bool operator==(const CalcValue& aOther) const {
return mLength == aOther.mLength &&
mPercent == aOther.mPercent &&
mHasPercent == aOther.mHasPercent;
}
bool operator!=(const Calc& aOther) const { return !(*this == aOther); }
bool operator!=(const CalcValue& aOther) const {
return !(*this == aOther);
}
};
// Reference counted calc() value. This is the type that is used to store
// the calc() value in nsStyleCoord.
struct Calc MOZ_FINAL : public CalcValue {
NS_INLINE_DECL_REFCOUNTING(Calc)
Calc() {}
private:
Calc(const Calc&) MOZ_DELETE;
~Calc() {}
Calc& operator=(const Calc&) MOZ_DELETE;
};
nsStyleCoord(nsStyleUnit aUnit = eStyleUnit_Null);
@ -75,11 +89,13 @@ public:
nsStyleCoord(float aValue, nsStyleUnit aUnit);
inline nsStyleCoord(const nsStyleCoord& aCopy);
inline nsStyleCoord(const nsStyleUnion& aValue, nsStyleUnit aUnit);
~nsStyleCoord() { Reset(); }
nsStyleCoord& operator=(const nsStyleCoord& aOther)
{
mUnit = aOther.mUnit;
mValue = aOther.mValue;
if (this != &aOther) {
SetValue(mUnit, mValue, aOther);
}
return *this;
}
bool operator==(const nsStyleCoord& aOther) const;
@ -94,12 +110,20 @@ public:
return eStyleUnit_Degree <= mUnit && mUnit <= eStyleUnit_Turn;
}
static bool IsCalcUnit(nsStyleUnit aUnit) {
return aUnit == eStyleUnit_Calc;
}
static bool IsPointerUnit(nsStyleUnit aUnit) {
return IsCalcUnit(aUnit);
}
bool IsCalcUnit() const {
return eStyleUnit_Calc == mUnit;
return IsCalcUnit(mUnit);
}
bool IsPointerValue() const {
return IsCalcUnit();
return IsPointerUnit(mUnit);
}
bool IsCoordPercentCalcUnit() const {
@ -132,10 +156,12 @@ public:
double GetAngleValueInRadians() const;
float GetFlexFractionValue() const;
Calc* GetCalcValue() const;
void GetUnionValue(nsStyleUnion& aValue) const;
uint32_t HashValue(uint32_t aHash) const;
void Reset(); // sets to null
// Sets to null and releases any refcounted objects. Only use this if the
// object is initialized (i.e. don't use it in nsStyleCoord constructors).
void Reset();
void SetCoordValue(nscoord aValue);
void SetIntValue(int32_t aValue, nsStyleUnit aUnit);
void SetPercentValue(float aValue);
@ -147,6 +173,20 @@ public:
void SetNoneValue();
void SetCalcValue(Calc* aValue);
// Resets a coord represented by a unit/value pair.
static inline void Reset(nsStyleUnit& aUnit, nsStyleUnion& aValue);
// Sets a coord represented by a unit/value pair from a second
// unit/value pair.
static inline void SetValue(nsStyleUnit& aUnit,
nsStyleUnion& aValue,
nsStyleUnit aOtherUnit,
const nsStyleUnion& aOtherValue);
// Sets a coord represented by a unit/value pair from an nsStyleCoord.
static inline void SetValue(nsStyleUnit& aUnit, nsStyleUnion& aValue,
const nsStyleCoord& aOther);
private:
nsStyleUnit mUnit;
nsStyleUnion mValue;
@ -160,8 +200,10 @@ private:
class nsStyleSides {
public:
nsStyleSides();
nsStyleSides(const nsStyleSides&);
~nsStyleSides();
// nsStyleSides& operator=(const nsStyleSides& aCopy); // use compiler's version
nsStyleSides& operator=(const nsStyleSides& aCopy);
bool operator==(const nsStyleSides& aOther) const;
bool operator!=(const nsStyleSides& aOther) const;
@ -177,7 +219,10 @@ public:
inline nsStyleCoord GetRight() const;
inline nsStyleCoord GetBottom() const;
void Reset();
// Sets each side to null and releases any refcounted objects. Only use this
// if the object is initialized (i.e. don't use it in nsStyleSides
// constructors).
void Reset();
inline void Set(mozilla::css::Side aSide, const nsStyleCoord& aCoord);
inline void SetLeft(const nsStyleCoord& aCoord);
@ -198,9 +243,11 @@ protected:
class nsStyleCorners {
public:
nsStyleCorners();
nsStyleCorners(const nsStyleCorners&);
~nsStyleCorners();
// use compiler's version
//nsStyleCorners& operator=(const nsStyleCorners& aCopy);
nsStyleCorners& operator=(const nsStyleCorners& aCopy);
bool operator==(const nsStyleCorners& aOther) const;
bool operator!=(const nsStyleCorners& aOther) const;
@ -209,7 +256,10 @@ public:
inline nsStyleCoord Get(uint8_t aHalfCorner) const;
void Reset();
// Sets each corner to null and releases any refcounted objects. Only use
// this if the object is initialized (i.e. don't use it in nsStyleCorners
// constructors).
void Reset();
inline void Set(uint8_t aHalfCorner, const nsStyleCoord& aCoord);
@ -228,26 +278,16 @@ inline nsStyleCoord::nsStyleCoord(nscoord aValue, CoordConstructorType)
mValue.mInt = aValue;
}
// FIXME: In C++0x we can rely on the default copy constructor since
// default copy construction is defined properly for unions. But when
// can we actually use that? (It seems to work in gcc 4.4.)
inline nsStyleCoord::nsStyleCoord(const nsStyleCoord& aCopy)
: mUnit(aCopy.mUnit)
: mUnit(eStyleUnit_Null)
{
if ((eStyleUnit_Percent <= mUnit) && (mUnit < eStyleUnit_Coord)) {
mValue.mFloat = aCopy.mValue.mFloat;
}
else if (IsPointerValue()) {
mValue.mPointer = aCopy.mValue.mPointer;
}
else {
mValue.mInt = aCopy.mValue.mInt;
}
SetValue(mUnit, mValue, aCopy);
}
inline nsStyleCoord::nsStyleCoord(const nsStyleUnion& aValue, nsStyleUnit aUnit)
: mUnit(aUnit), mValue(aValue)
: mUnit(eStyleUnit_Null)
{
SetValue(mUnit, mValue, aUnit, aValue);
}
inline bool nsStyleCoord::operator!=(const nsStyleCoord& aOther) const
@ -321,12 +361,52 @@ inline nsStyleCoord::Calc* nsStyleCoord::GetCalcValue() const
return nullptr;
}
inline void nsStyleCoord::GetUnionValue(nsStyleUnion& aValue) const
/* static */ inline void
nsStyleCoord::Reset(nsStyleUnit& aUnit, nsStyleUnion& aValue)
{
aValue = mValue;
MOZ_ASSERT(aUnit <= eStyleUnit_MAX,
"calling Reset on uninitialized nsStyleCoord?");
switch (aUnit) {
case eStyleUnit_Calc:
static_cast<Calc*>(aValue.mPointer)->Release();
break;
default:
MOZ_ASSERT(!IsPointerUnit(aUnit), "check pointer refcounting logic");
}
aUnit = eStyleUnit_Null;
aValue.mInt = 0;
}
/* static */ inline void
nsStyleCoord::SetValue(nsStyleUnit& aUnit,
nsStyleUnion& aValue,
nsStyleUnit aOtherUnit,
const nsStyleUnion& aOtherValue)
{
Reset(aUnit, aValue);
aUnit = aOtherUnit;
aValue = aOtherValue;
switch (aUnit) {
case eStyleUnit_Calc:
static_cast<Calc*>(aValue.mPointer)->AddRef();
break;
default:
MOZ_ASSERT(!IsPointerUnit(aUnit), "check pointer refcounting logic");
}
}
/* static */ inline void
nsStyleCoord::SetValue(nsStyleUnit& aUnit, nsStyleUnion& aValue,
const nsStyleCoord& aOther)
{
SetValue(aUnit, aValue, aOther.mUnit, aOther.mValue);
}
// -------------------------
// nsStyleSides inlines
//
@ -387,8 +467,7 @@ inline nsStyleCoord nsStyleSides::GetBottom() const
inline void nsStyleSides::Set(mozilla::css::Side aSide, const nsStyleCoord& aCoord)
{
mUnits[aSide] = aCoord.GetUnit();
aCoord.GetUnionValue(mValues[aSide]);
nsStyleCoord::SetValue(mUnits[aSide], mValues[aSide], aCoord);
}
inline void nsStyleSides::SetLeft(const nsStyleCoord& aCoord)
@ -431,8 +510,7 @@ inline nsStyleCoord nsStyleCorners::Get(uint8_t aCorner) const
inline void nsStyleCorners::Set(uint8_t aCorner, const nsStyleCoord& aCoord)
{
mUnits[aCorner] = aCoord.GetUnit();
aCoord.GetUnionValue(mValues[aCorner]);
nsStyleCoord::SetValue(mUnits[aCorner], mValues[aCorner], aCoord);
}
#endif /* nsStyleCoord_h___ */

View File

@ -358,7 +358,7 @@ struct nsStyleBackground {
struct Position;
friend struct Position;
struct Position {
typedef nsStyleCoord::Calc PositionCoord;
typedef nsStyleCoord::CalcValue PositionCoord;
PositionCoord mXPosition, mYPosition;
// Initialize nothing
@ -385,7 +385,7 @@ struct nsStyleBackground {
struct Size;
friend struct Size;
struct Size {
struct Dimension : public nsStyleCoord::Calc {
struct Dimension : public nsStyleCoord::CalcValue {
nscoord ResolveLengthPercentage(nscoord aAvailable) const {
double d = double(mPercent) * double(aAvailable) + double(mLength);
if (d < 0.0)