mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-23 17:07:31 +09:00
Fix app-unit rounding for border width edges
This commit is contained in:
parent
8f053624dd
commit
cf8b773656
2 changed files with 127 additions and 21 deletions
|
|
@ -319,6 +319,11 @@ nsRuleNode::EnsureInlineDisplay(StyleDisplay& display)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class AppUnitRounding {
|
||||||
|
Default,
|
||||||
|
TowardZero
|
||||||
|
};
|
||||||
|
|
||||||
static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||||
nscoord aFontSize,
|
nscoord aFontSize,
|
||||||
const nsStyleFont* aStyleFont,
|
const nsStyleFont* aStyleFont,
|
||||||
|
|
@ -326,7 +331,9 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool aUseProvidedRootEmSize,
|
bool aUseProvidedRootEmSize,
|
||||||
bool aUseUserFontSet,
|
bool aUseUserFontSet,
|
||||||
RuleNodeCacheConditions& aConditions);
|
RuleNodeCacheConditions& aConditions,
|
||||||
|
AppUnitRounding aRounding =
|
||||||
|
AppUnitRounding::Default);
|
||||||
|
|
||||||
struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
|
struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
|
||||||
public css::NumbersAlreadyNormalizedOps
|
public css::NumbersAlreadyNormalizedOps
|
||||||
|
|
@ -339,18 +346,21 @@ struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
|
||||||
const bool mUseProvidedRootEmSize;
|
const bool mUseProvidedRootEmSize;
|
||||||
const bool mUseUserFontSet;
|
const bool mUseUserFontSet;
|
||||||
RuleNodeCacheConditions& mConditions;
|
RuleNodeCacheConditions& mConditions;
|
||||||
|
const AppUnitRounding mRounding;
|
||||||
|
|
||||||
CalcLengthCalcOps(nscoord aFontSize, const nsStyleFont* aStyleFont,
|
CalcLengthCalcOps(nscoord aFontSize, const nsStyleFont* aStyleFont,
|
||||||
nsStyleContext* aStyleContext, nsPresContext* aPresContext,
|
nsStyleContext* aStyleContext, nsPresContext* aPresContext,
|
||||||
bool aUseProvidedRootEmSize, bool aUseUserFontSet,
|
bool aUseProvidedRootEmSize, bool aUseUserFontSet,
|
||||||
RuleNodeCacheConditions& aConditions)
|
RuleNodeCacheConditions& aConditions,
|
||||||
|
AppUnitRounding aRounding)
|
||||||
: mFontSize(aFontSize),
|
: mFontSize(aFontSize),
|
||||||
mStyleFont(aStyleFont),
|
mStyleFont(aStyleFont),
|
||||||
mStyleContext(aStyleContext),
|
mStyleContext(aStyleContext),
|
||||||
mPresContext(aPresContext),
|
mPresContext(aPresContext),
|
||||||
mUseProvidedRootEmSize(aUseProvidedRootEmSize),
|
mUseProvidedRootEmSize(aUseProvidedRootEmSize),
|
||||||
mUseUserFontSet(aUseUserFontSet),
|
mUseUserFontSet(aUseUserFontSet),
|
||||||
mConditions(aConditions)
|
mConditions(aConditions),
|
||||||
|
mRounding(aRounding)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -358,15 +368,84 @@ struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
|
||||||
{
|
{
|
||||||
return CalcLengthWith(aValue, mFontSize, mStyleFont,
|
return CalcLengthWith(aValue, mFontSize, mStyleFont,
|
||||||
mStyleContext, mPresContext, mUseProvidedRootEmSize,
|
mStyleContext, mPresContext, mUseProvidedRootEmSize,
|
||||||
mUseUserFontSet, mConditions);
|
mUseUserFontSet, mConditions, mRounding);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline nscoord ScaleCoordRound(const nsCSSValue& aValue, float aFactor)
|
static inline nscoord
|
||||||
|
ScaleCoordWithRounding(const nsCSSValue& aValue, float aFactor,
|
||||||
|
AppUnitRounding aRounding)
|
||||||
{
|
{
|
||||||
|
if (aRounding == AppUnitRounding::TowardZero) {
|
||||||
|
return NSToCoordTruncClamped(aValue.GetFloatValue() * aFactor);
|
||||||
|
}
|
||||||
return NSToCoordRoundWithClamp(aValue.GetFloatValue() * aFactor);
|
return NSToCoordRoundWithClamp(aValue.GetFloatValue() * aFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline nscoord
|
||||||
|
CSSPixelsToAppUnitsWithRounding(float aPixels, AppUnitRounding aRounding)
|
||||||
|
{
|
||||||
|
if (aRounding == AppUnitRounding::TowardZero) {
|
||||||
|
return NSToCoordTruncClamped(double(aPixels) *
|
||||||
|
nsPresContext::AppUnitsPerCSSPixel());
|
||||||
|
}
|
||||||
|
return nsPresContext::CSSPixelsToAppUnits(aPixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static nscoord
|
||||||
|
GetFixedLengthWithRounding(const nsCSSValue& aValue,
|
||||||
|
nsPresContext* aPresContext,
|
||||||
|
AppUnitRounding aRounding)
|
||||||
|
{
|
||||||
|
if (aRounding == AppUnitRounding::Default) {
|
||||||
|
return aValue.GetFixedLength(aPresContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_PhysicalMillimeter,
|
||||||
|
"not a fixed length unit");
|
||||||
|
double inches = double(aValue.GetFloatValue()) / MM_PER_INCH_FLOAT;
|
||||||
|
return NSToCoordTruncClamped(
|
||||||
|
inches * aPresContext->DeviceContext()->AppUnitsPerPhysicalInch());
|
||||||
|
}
|
||||||
|
|
||||||
|
static nscoord
|
||||||
|
GetPixelLengthWithRounding(const nsCSSValue& aValue,
|
||||||
|
AppUnitRounding aRounding)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aValue.IsPixelLengthUnit(), "not a pixel length unit");
|
||||||
|
|
||||||
|
double scaleFactor;
|
||||||
|
switch (aValue.GetUnit()) {
|
||||||
|
case eCSSUnit_Pixel:
|
||||||
|
return CSSPixelsToAppUnitsWithRounding(aValue.GetFloatValue(),
|
||||||
|
aRounding);
|
||||||
|
case eCSSUnit_Pica:
|
||||||
|
scaleFactor = 16.0;
|
||||||
|
break;
|
||||||
|
case eCSSUnit_Point:
|
||||||
|
scaleFactor = 4.0 / 3.0;
|
||||||
|
break;
|
||||||
|
case eCSSUnit_Inch:
|
||||||
|
scaleFactor = 96.0;
|
||||||
|
break;
|
||||||
|
case eCSSUnit_Millimeter:
|
||||||
|
scaleFactor = 96.0 / 25.4;
|
||||||
|
break;
|
||||||
|
case eCSSUnit_Centimeter:
|
||||||
|
scaleFactor = 96.0 / 2.54;
|
||||||
|
break;
|
||||||
|
case eCSSUnit_Quarter:
|
||||||
|
scaleFactor = 96.0 / 101.6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NS_ERROR("should never get here");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CSSPixelsToAppUnitsWithRounding(
|
||||||
|
float(double(aValue.GetFloatValue()) * scaleFactor), aRounding);
|
||||||
|
}
|
||||||
|
|
||||||
static inline nscoord ScaleViewportCoordTrunc(const nsCSSValue& aValue,
|
static inline nscoord ScaleViewportCoordTrunc(const nsCSSValue& aValue,
|
||||||
nscoord aViewportSize)
|
nscoord aViewportSize)
|
||||||
{
|
{
|
||||||
|
|
@ -465,7 +544,8 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||||
// except when called from
|
// except when called from
|
||||||
// CalcLengthWithInitialFont.
|
// CalcLengthWithInitialFont.
|
||||||
bool aUseUserFontSet,
|
bool aUseUserFontSet,
|
||||||
RuleNodeCacheConditions& aConditions)
|
RuleNodeCacheConditions& aConditions,
|
||||||
|
AppUnitRounding aRounding)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(aValue.IsLengthUnit() || aValue.IsCalcUnit(),
|
NS_ASSERTION(aValue.IsLengthUnit() || aValue.IsCalcUnit(),
|
||||||
"not a length or calc unit");
|
"not a length or calc unit");
|
||||||
|
|
@ -476,10 +556,10 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||||
NS_ASSERTION(aPresContext, "Must have prescontext");
|
NS_ASSERTION(aPresContext, "Must have prescontext");
|
||||||
|
|
||||||
if (aValue.IsFixedLengthUnit()) {
|
if (aValue.IsFixedLengthUnit()) {
|
||||||
return aValue.GetFixedLength(aPresContext);
|
return GetFixedLengthWithRounding(aValue, aPresContext, aRounding);
|
||||||
}
|
}
|
||||||
if (aValue.IsPixelLengthUnit()) {
|
if (aValue.IsPixelLengthUnit()) {
|
||||||
return aValue.GetPixelLength();
|
return GetPixelLengthWithRounding(aValue, aRounding);
|
||||||
}
|
}
|
||||||
if (aValue.IsCalcUnit()) {
|
if (aValue.IsCalcUnit()) {
|
||||||
// For properties for which lengths are the *only* units accepted in
|
// For properties for which lengths are the *only* units accepted in
|
||||||
|
|
@ -490,7 +570,7 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||||
CalcLengthCalcOps ops(aFontSize, aStyleFont,
|
CalcLengthCalcOps ops(aFontSize, aStyleFont,
|
||||||
aStyleContext, aPresContext,
|
aStyleContext, aPresContext,
|
||||||
aUseProvidedRootEmSize, aUseUserFontSet,
|
aUseProvidedRootEmSize, aUseUserFontSet,
|
||||||
aConditions);
|
aConditions, aRounding);
|
||||||
return css::ComputeCalc(aValue, ops);
|
return css::ComputeCalc(aValue, ops);
|
||||||
}
|
}
|
||||||
switch (aValue.GetUnit()) {
|
switch (aValue.GetUnit()) {
|
||||||
|
|
@ -623,7 +703,7 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||||
rootFontSize = rootStyleFont->mFont.size;
|
rootFontSize = rootStyleFont->mFont.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ScaleCoordRound(aValue, float(rootFontSize));
|
return ScaleCoordWithRounding(aValue, float(rootFontSize), aRounding);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Fall through to the code for units that can't be stored in the
|
// Fall through to the code for units that can't be stored in the
|
||||||
|
|
@ -648,7 +728,7 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||||
// CSS2.1 specifies that this unit scales to the computed font
|
// CSS2.1 specifies that this unit scales to the computed font
|
||||||
// size, not the em-width in the font metrics, despite the name.
|
// size, not the em-width in the font metrics, despite the name.
|
||||||
aConditions.SetFontSizeDependency(aFontSize);
|
aConditions.SetFontSizeDependency(aFontSize);
|
||||||
return ScaleCoordRound(aValue, float(aFontSize));
|
return ScaleCoordWithRounding(aValue, float(aFontSize), aRounding);
|
||||||
}
|
}
|
||||||
case eCSSUnit_XHeight: {
|
case eCSSUnit_XHeight: {
|
||||||
aPresContext->SetUsesExChUnits(true);
|
aPresContext->SetUsesExChUnits(true);
|
||||||
|
|
@ -656,7 +736,7 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||||
GetMetricsFor(aPresContext, aStyleContext, styleFont,
|
GetMetricsFor(aPresContext, aStyleContext, styleFont,
|
||||||
aFontSize, aUseUserFontSet);
|
aFontSize, aUseUserFontSet);
|
||||||
aConditions.SetUncacheable();
|
aConditions.SetUncacheable();
|
||||||
return ScaleCoordRound(aValue, float(fm->XHeight()));
|
return ScaleCoordWithRounding(aValue, float(fm->XHeight()), aRounding);
|
||||||
}
|
}
|
||||||
case eCSSUnit_Char: {
|
case eCSSUnit_Char: {
|
||||||
aPresContext->SetUsesExChUnits(true);
|
aPresContext->SetUsesExChUnits(true);
|
||||||
|
|
@ -668,8 +748,9 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||||
GetMetrics(fm->Orientation()).zeroOrAveCharWidth;
|
GetMetrics(fm->Orientation()).zeroOrAveCharWidth;
|
||||||
|
|
||||||
aConditions.SetUncacheable();
|
aConditions.SetUncacheable();
|
||||||
return ScaleCoordRound(aValue, ceil(aPresContext->AppUnitsPerDevPixel() *
|
return ScaleCoordWithRounding(
|
||||||
zeroWidth));
|
aValue, ceil(aPresContext->AppUnitsPerDevPixel() * zeroWidth),
|
||||||
|
aRounding);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
NS_NOTREACHED("unexpected unit");
|
NS_NOTREACHED("unexpected unit");
|
||||||
|
|
@ -701,6 +782,20 @@ static inline nscoord CalcLength(const nsCSSValue& aValue,
|
||||||
aPresContext, aConditions);
|
aPresContext, aConditions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline nscoord
|
||||||
|
CalcLengthTowardZero(const nsCSSValue& aValue,
|
||||||
|
nsStyleContext* aStyleContext,
|
||||||
|
nsPresContext* aPresContext,
|
||||||
|
RuleNodeCacheConditions& aConditions)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aStyleContext, "Must have style data");
|
||||||
|
|
||||||
|
return CalcLengthWith(aValue, -1, nullptr,
|
||||||
|
aStyleContext, aPresContext,
|
||||||
|
false, true, aConditions,
|
||||||
|
AppUnitRounding::TowardZero);
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ nscoord
|
/* static */ nscoord
|
||||||
nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
|
nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
|
||||||
const nsCSSValue& aValue)
|
const nsCSSValue& aValue)
|
||||||
|
|
@ -8048,13 +8143,11 @@ nsRuleNode::ComputeBorderData(void* aStartStruct,
|
||||||
"Unexpected enum value");
|
"Unexpected enum value");
|
||||||
border->SetBorderWidth(side,
|
border->SetBorderWidth(side,
|
||||||
(mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
|
(mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
|
||||||
// OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
|
} else if (value.IsLengthUnit() || value.IsCalcUnit()) {
|
||||||
} else if (SetCoord(value, coord, nsStyleCoord(),
|
|
||||||
SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
|
|
||||||
aContext, mPresContext, conditions)) {
|
|
||||||
NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
|
|
||||||
// clamp negative calc() to 0.
|
// clamp negative calc() to 0.
|
||||||
border->SetBorderWidth(side, std::max(coord.GetCoordValue(), 0));
|
border->SetBorderWidth(side,
|
||||||
|
std::max(CalcLengthTowardZero(value, aContext, mPresContext,
|
||||||
|
conditions), 0));
|
||||||
} else if (eCSSUnit_Inherit == value.GetUnit()) {
|
} else if (eCSSUnit_Inherit == value.GetUnit()) {
|
||||||
conditions.SetUncacheable();
|
conditions.SetUncacheable();
|
||||||
border->SetBorderWidth(side,
|
border->SetBorderWidth(side,
|
||||||
|
|
@ -8336,6 +8429,11 @@ nsRuleNode::ComputeOutlineData(void* aStartStruct,
|
||||||
eCSSUnit_Revert == outlineWidthValue->GetUnit()) {
|
eCSSUnit_Revert == outlineWidthValue->GetUnit()) {
|
||||||
outline->mOutlineWidth =
|
outline->mOutlineWidth =
|
||||||
nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
|
nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
|
||||||
|
} else if (outlineWidthValue->IsLengthUnit() ||
|
||||||
|
outlineWidthValue->IsCalcUnit()) {
|
||||||
|
outline->mOutlineWidth.SetCoordValue(
|
||||||
|
CalcLengthTowardZero(*outlineWidthValue, aContext, mPresContext,
|
||||||
|
conditions));
|
||||||
} else {
|
} else {
|
||||||
SetCoord(*outlineWidthValue, outline->mOutlineWidth,
|
SetCoord(*outlineWidthValue, outline->mOutlineWidth,
|
||||||
parentOutline->mOutlineWidth,
|
parentOutline->mOutlineWidth,
|
||||||
|
|
@ -8346,7 +8444,13 @@ nsRuleNode::ComputeOutlineData(void* aStartStruct,
|
||||||
// outline-offset: length, inherit
|
// outline-offset: length, inherit
|
||||||
nsStyleCoord tempCoord;
|
nsStyleCoord tempCoord;
|
||||||
const nsCSSValue* outlineOffsetValue = aRuleData->ValueForOutlineOffset();
|
const nsCSSValue* outlineOffsetValue = aRuleData->ValueForOutlineOffset();
|
||||||
if (SetCoord(*outlineOffsetValue, tempCoord,
|
if (outlineOffsetValue->IsLengthUnit() || outlineOffsetValue->IsCalcUnit()) {
|
||||||
|
outline->mOutlineOffset =
|
||||||
|
NS_ROUND_OFFSET_TO_PIXELS(
|
||||||
|
CalcLengthTowardZero(*outlineOffsetValue, aContext, mPresContext,
|
||||||
|
conditions),
|
||||||
|
mPresContext->AppUnitsPerDevPixel());
|
||||||
|
} else if (SetCoord(*outlineOffsetValue, tempCoord,
|
||||||
nsStyleCoord(parentOutline->mOutlineOffset,
|
nsStyleCoord(parentOutline->mOutlineOffset,
|
||||||
nsStyleCoord::CoordConstructor),
|
nsStyleCoord::CoordConstructor),
|
||||||
SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
|
SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ var tests = [
|
||||||
["2px", "2px"],
|
["2px", "2px"],
|
||||||
["2.75px", "2px"],
|
["2.75px", "2px"],
|
||||||
["2.999px", "2px"],
|
["2.999px", "2px"],
|
||||||
|
["3px", "3px"],
|
||||||
|
["3.001px", "3px"],
|
||||||
];
|
];
|
||||||
|
|
||||||
function checkWidth(property, setupProperty, setupValue) {
|
function checkWidth(property, setupProperty, setupValue) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue