/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* representation of length values in computed style data */ #include "nsStyleCoord.h" #include "mozilla/HashFunctions.h" #include "mozilla/PodOperations.h" using namespace mozilla; nsStyleCoord::nsStyleCoord(nsStyleUnit aUnit) : mUnit(aUnit) { NS_ASSERTION(aUnit < eStyleUnit_Percent, "not a valueless unit"); if (aUnit >= eStyleUnit_Percent) { mUnit = eStyleUnit_Null; } mValue.mInt = 0; } nsStyleCoord::nsStyleCoord(int32_t aValue, nsStyleUnit aUnit) : mUnit(aUnit) { //if you want to pass in eStyleUnit_Coord, don't. instead, use the //constructor just above this one... MMP NS_ASSERTION((aUnit == eStyleUnit_Enumerated) || (aUnit == eStyleUnit_Integer), "not an int value"); if ((aUnit == eStyleUnit_Enumerated) || (aUnit == eStyleUnit_Integer)) { mValue.mInt = aValue; } else { mUnit = eStyleUnit_Null; mValue.mInt = 0; } } nsStyleCoord::nsStyleCoord(float aValue, nsStyleUnit aUnit) : mUnit(aUnit) { if (aUnit < eStyleUnit_Percent || aUnit >= eStyleUnit_Coord) { NS_NOTREACHED("not a float value"); mUnit = eStyleUnit_Null; mValue.mInt = 0; } else { mValue.mFloat = aValue; } } bool nsStyleCoord::operator==(const nsStyleCoord& aOther) const { if (mUnit != aOther.mUnit) { return false; } switch (mUnit) { case eStyleUnit_Null: case eStyleUnit_Normal: case eStyleUnit_Auto: case eStyleUnit_None: return true; case eStyleUnit_Percent: case eStyleUnit_Factor: case eStyleUnit_Degree: case eStyleUnit_Grad: case eStyleUnit_Radian: case eStyleUnit_Turn: case eStyleUnit_FlexFraction: return mValue.mFloat == aOther.mValue.mFloat; case eStyleUnit_Coord: case eStyleUnit_Integer: case eStyleUnit_Enumerated: return mValue.mInt == aOther.mValue.mInt; case eStyleUnit_Calc: return *this->GetCalcValue() == *aOther.GetCalcValue(); } MOZ_ASSERT(false, "unexpected unit"); return false; } uint32_t nsStyleCoord::HashValue(uint32_t aHash = 0) const { aHash = mozilla::AddToHash(aHash, mUnit); switch (mUnit) { case eStyleUnit_Null: case eStyleUnit_Normal: case eStyleUnit_Auto: case eStyleUnit_None: return mozilla::AddToHash(aHash, true); case eStyleUnit_Percent: case eStyleUnit_Factor: case eStyleUnit_Degree: case eStyleUnit_Grad: case eStyleUnit_Radian: case eStyleUnit_Turn: case eStyleUnit_FlexFraction: return mozilla::AddToHash(aHash, mValue.mFloat); case eStyleUnit_Coord: case eStyleUnit_Integer: case eStyleUnit_Enumerated: return mozilla::AddToHash(aHash, mValue.mInt); case eStyleUnit_Calc: Calc* calcValue = GetCalcValue(); aHash = mozilla::AddToHash(aHash, calcValue->mLength); if (HasPercent()) { return mozilla::AddToHash(aHash, calcValue->mPercent); } return aHash; } MOZ_ASSERT(false, "unexpected unit"); return aHash; } void nsStyleCoord::Reset() { Reset(mUnit, mValue); } void nsStyleCoord::SetCoordValue(nscoord aValue) { Reset(); mUnit = eStyleUnit_Coord; mValue.mInt = aValue; } 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; } } 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 || aUnit == eStyleUnit_Turn) { mUnit = aUnit; mValue.mFloat = aValue; } else { NS_NOTREACHED("not an angle value"); } } 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; } // accessors that are not inlined double nsStyleCoord::GetAngleValueInDegrees() const { return GetAngleValueInRadians() * (180.0 / M_PI); } double nsStyleCoord::GetAngleValueInRadians() const { double angle = mValue.mFloat; switch (GetUnit()) { case eStyleUnit_Radian: return angle; case eStyleUnit_Turn: return angle * 2 * M_PI; case eStyleUnit_Degree: return angle * M_PI / 180.0; case eStyleUnit_Grad: return angle * M_PI / 200.0; default: NS_NOTREACHED("unrecognized angular unit"); return 0.0; } } nsStyleSides::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 { NS_FOR_CSS_SIDES(i) { if (nsStyleCoord(mValues[i], (nsStyleUnit)mUnits[i]) != nsStyleCoord(aOther.mValues[i], (nsStyleUnit)aOther.mUnits[i])) { return false; } } return true; } void nsStyleSides::Reset() { NS_FOR_CSS_SIDES(i) { nsStyleCoord::Reset(mUnits[i], mValues[i]); } } nsStyleCorners::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 nsStyleCorners::operator==(const nsStyleCorners& aOther) const { NS_FOR_CSS_HALF_CORNERS(i) { if (nsStyleCoord(mValues[i], (nsStyleUnit)mUnits[i]) != nsStyleCoord(aOther.mValues[i], (nsStyleUnit)aOther.mUnits[i])) { return false; } } return true; } void nsStyleCorners::Reset() { NS_FOR_CSS_HALF_CORNERS(i) { nsStyleCoord::Reset(mUnits[i], mValues[i]); } } // Validation of NS_SIDE_IS_VERTICAL and NS_HALF_CORNER_IS_X. #define CASE(side, result) \ static_assert(NS_SIDE_IS_VERTICAL(side) == result, \ "NS_SIDE_IS_VERTICAL is wrong") CASE(eSideTop, false); CASE(eSideRight, true); CASE(eSideBottom, false); CASE(eSideLeft, true); #undef CASE // Validation of HalfCornerIsX. #define CASE(corner, result) \ static_assert(HalfCornerIsX(corner) == result, \ "HalfCornerIsX is wrong") CASE(eCornerTopLeftX, true); CASE(eCornerTopLeftY, false); CASE(eCornerTopRightX, true); CASE(eCornerTopRightY, false); CASE(eCornerBottomRightX, true); CASE(eCornerBottomRightY, false); CASE(eCornerBottomLeftX, true); CASE(eCornerBottomLeftY, false); #undef CASE // Validation of HalfToFullCorner. #define CASE(corner, result) \ static_assert(HalfToFullCorner(corner) == result, \ "HalfToFullCorner is wrong") CASE(eCornerTopLeftX, eCornerTopLeft); CASE(eCornerTopLeftY, eCornerTopLeft); CASE(eCornerTopRightX, eCornerTopRight); CASE(eCornerTopRightY, eCornerTopRight); CASE(eCornerBottomRightX, eCornerBottomRight); CASE(eCornerBottomRightY, eCornerBottomRight); CASE(eCornerBottomLeftX, eCornerBottomLeft); CASE(eCornerBottomLeftY, eCornerBottomLeft); #undef CASE // Validation of FullToHalfCorner. #define CASE(corner, vert, result) \ static_assert(FullToHalfCorner(corner, vert) == result, \ "FullToHalfCorner is wrong") CASE(eCornerTopLeft, false, eCornerTopLeftX); CASE(eCornerTopLeft, true, eCornerTopLeftY); CASE(eCornerTopRight, false, eCornerTopRightX); CASE(eCornerTopRight, true, eCornerTopRightY); CASE(eCornerBottomRight, false, eCornerBottomRightX); CASE(eCornerBottomRight, true, eCornerBottomRightY); CASE(eCornerBottomLeft, false, eCornerBottomLeftX); CASE(eCornerBottomLeft, true, eCornerBottomLeftY); #undef CASE // Validation of NS_SIDE_TO_{FULL,HALF}_CORNER. #define CASE(side, second, result) \ static_assert(NS_SIDE_TO_FULL_CORNER(side, second) == result, \ "NS_SIDE_TO_FULL_CORNER is wrong") CASE(eSideTop, false, eCornerTopLeft); CASE(eSideTop, true, eCornerTopRight); CASE(eSideRight, false, eCornerTopRight); CASE(eSideRight, true, eCornerBottomRight); CASE(eSideBottom, false, eCornerBottomRight); CASE(eSideBottom, true, eCornerBottomLeft); CASE(eSideLeft, false, eCornerBottomLeft); CASE(eSideLeft, true, eCornerTopLeft); #undef CASE #define CASE(side, second, parallel, result) \ static_assert(NS_SIDE_TO_HALF_CORNER(side, second, parallel) == result, \ "NS_SIDE_TO_HALF_CORNER is wrong") CASE(eSideTop, false, true, eCornerTopLeftX); CASE(eSideTop, false, false, eCornerTopLeftY); CASE(eSideTop, true, true, eCornerTopRightX); CASE(eSideTop, true, false, eCornerTopRightY); CASE(eSideRight, false, false, eCornerTopRightX); CASE(eSideRight, false, true, eCornerTopRightY); CASE(eSideRight, true, false, eCornerBottomRightX); CASE(eSideRight, true, true, eCornerBottomRightY); CASE(eSideBottom, false, true, eCornerBottomRightX); CASE(eSideBottom, false, false, eCornerBottomRightY); CASE(eSideBottom, true, true, eCornerBottomLeftX); CASE(eSideBottom, true, false, eCornerBottomLeftY); CASE(eSideLeft, false, false, eCornerBottomLeftX); CASE(eSideLeft, false, true, eCornerBottomLeftY); CASE(eSideLeft, true, false, eCornerTopLeftX); CASE(eSideLeft, true, true, eCornerTopLeftY); #undef CASE