gecko-dev/layout/style/nsStyleCoord.cpp

298 строки
8.7 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "mozilla/HashFunctions.h"
#include "mozilla/PodOperations.h"
// nsStyleCoord.h must not be the first header in a unified source file,
// otherwise it may not build with MSVC due to a bug in our STL wrapper.
// See bug 1331102.
#include "nsStyleCoord.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) {
MOZ_ASSERT_UNREACHABLE("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_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;
}
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::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 {
// Note that this extends the value from float to double.
return GetAngleValue();
}
double nsStyleCoord::GetAngleValueInRadians() const {
return GetAngleValueInDegrees() * M_PI / 180.0;
}
nscoord nsStyleCoord::ComputeComputedCalc(nscoord aPercentageBasis) const {
Calc* calc = GetCalcValue();
return calc->mLength +
NSToCoordFloorClamped(aPercentageBasis * calc->mPercent);
}
nscoord nsStyleCoord::ComputeCoordPercentCalc(nscoord aPercentageBasis) const {
switch (GetUnit()) {
case eStyleUnit_Coord:
return GetCoordValue();
case eStyleUnit_Percent:
return NSToCoordFloorClamped(aPercentageBasis * GetPercentValue());
case eStyleUnit_Calc:
return ComputeComputedCalc(aPercentageBasis);
default:
MOZ_ASSERT_UNREACHABLE("Unexpected unit!");
return 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]); }
}
// Validation of SideIsVertical.
#define CASE(side, result) \
static_assert(SideIsVertical(side) == result, "SideIsVertical 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 SideToFullCorner.
#define CASE(side, second, result) \
static_assert(SideToFullCorner(side, second) == result, \
"SideToFullCorner 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
// Validation of SideToHalfCorner.
#define CASE(side, second, parallel, result) \
static_assert(SideToHalfCorner(side, second, parallel) == result, \
"SideToHalfCorner 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