mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-25 09:57:32 +09:00
Issue #1826 - Canonicalize nested calc() serialization
This commit is contained in:
parent
adde59de74
commit
8af3f489da
2 changed files with 227 additions and 2 deletions
|
|
@ -1019,6 +1019,209 @@ private:
|
||||||
nsCSSValue::Serialization mValueSerialization;
|
nsCSSValue::Serialization mValueSerialization;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CSSValueReduceNumberCalcOps : public BasicFloatCalcOps,
|
||||||
|
public CSSValueInputCalcOps
|
||||||
|
{
|
||||||
|
result_type ComputeLeafValue(const nsCSSValue& aValue)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
|
||||||
|
return aValue.GetFloatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
float ComputeNumber(const nsCSSValue& aValue)
|
||||||
|
{
|
||||||
|
return css::ComputeCalc(aValue, *this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CSSValueCalcLengthTerm {
|
||||||
|
nsCSSUnit mUnit;
|
||||||
|
float mValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CSSValueLengthPercentCalcAccumulator {
|
||||||
|
AutoTArray<CSSValueCalcLengthTerm, 8> mLengths;
|
||||||
|
float mPercent = 0.0f;
|
||||||
|
bool mSawPercent = false;
|
||||||
|
|
||||||
|
void AddLength(nsCSSUnit aUnit, float aValue)
|
||||||
|
{
|
||||||
|
for (CSSValueCalcLengthTerm& term : mLengths) {
|
||||||
|
if (term.mUnit == aUnit) {
|
||||||
|
term.mValue += aValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSSValueCalcLengthTerm& term = *mLengths.AppendElement();
|
||||||
|
term.mUnit = aUnit;
|
||||||
|
term.mValue = aValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
IsNearlyZero(float aValue)
|
||||||
|
{
|
||||||
|
return aValue > -0.000001f && aValue < 0.000001f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ComputeCalcNumberValue(const nsCSSValue& aValue, float& aResult)
|
||||||
|
{
|
||||||
|
if (aValue.GetUnit() == eCSSUnit_Number) {
|
||||||
|
aResult = aValue.GetFloatValue();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aValue.IsCalcUnit()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSSValueReduceNumberCalcOps ops;
|
||||||
|
aResult = css::ComputeCalc(aValue, ops);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
AccumulateCalcLengthPercentTerms(
|
||||||
|
const nsCSSValue& aValue,
|
||||||
|
float aScale,
|
||||||
|
CSSValueLengthPercentCalcAccumulator& aAccumulator)
|
||||||
|
{
|
||||||
|
switch (aValue.GetUnit()) {
|
||||||
|
case eCSSUnit_Calc: {
|
||||||
|
const nsCSSValue::Array* array = aValue.GetArrayValue();
|
||||||
|
MOZ_ASSERT(array->Count() == 1, "unexpected length");
|
||||||
|
return AccumulateCalcLengthPercentTerms(array->Item(0), aScale,
|
||||||
|
aAccumulator);
|
||||||
|
}
|
||||||
|
|
||||||
|
case eCSSUnit_Calc_Plus:
|
||||||
|
case eCSSUnit_Calc_Minus: {
|
||||||
|
const nsCSSValue::Array* array = aValue.GetArrayValue();
|
||||||
|
MOZ_ASSERT(array->Count() == 2, "unexpected length");
|
||||||
|
if (!AccumulateCalcLengthPercentTerms(array->Item(0), aScale,
|
||||||
|
aAccumulator)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
float rhsScale = aValue.GetUnit() == eCSSUnit_Calc_Plus
|
||||||
|
? aScale
|
||||||
|
: -aScale;
|
||||||
|
return AccumulateCalcLengthPercentTerms(array->Item(1), rhsScale,
|
||||||
|
aAccumulator);
|
||||||
|
}
|
||||||
|
|
||||||
|
case eCSSUnit_Calc_Times_L:
|
||||||
|
case eCSSUnit_Calc_Times_R:
|
||||||
|
case eCSSUnit_Calc_Divided: {
|
||||||
|
const nsCSSValue::Array* array = aValue.GetArrayValue();
|
||||||
|
MOZ_ASSERT(array->Count() == 2, "unexpected length");
|
||||||
|
|
||||||
|
const nsCSSValue* value = &array->Item(0);
|
||||||
|
const nsCSSValue* factorValue = &array->Item(1);
|
||||||
|
if (aValue.GetUnit() == eCSSUnit_Calc_Times_L) {
|
||||||
|
value = &array->Item(1);
|
||||||
|
factorValue = &array->Item(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float factor;
|
||||||
|
if (!ComputeCalcNumberValue(*factorValue, factor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (aValue.GetUnit() == eCSSUnit_Calc_Divided) {
|
||||||
|
factor = 1.0f / factor;
|
||||||
|
}
|
||||||
|
return AccumulateCalcLengthPercentTerms(*value, aScale * factor,
|
||||||
|
aAccumulator);
|
||||||
|
}
|
||||||
|
|
||||||
|
case eCSSUnit_Percent:
|
||||||
|
aAccumulator.mSawPercent = true;
|
||||||
|
aAccumulator.mPercent += aScale * aValue.GetPercentValue();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aValue.IsLengthUnit()) {
|
||||||
|
aAccumulator.AddLength(aValue.GetUnit(), aScale * aValue.GetFloatValue());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
AppendSerializedCalcLeafValue(nsCSSPropertyID aProperty,
|
||||||
|
nsAString& aResult,
|
||||||
|
nsCSSValue::Serialization aSerialization,
|
||||||
|
nsCSSUnit aUnit,
|
||||||
|
float aValue)
|
||||||
|
{
|
||||||
|
nsCSSValue value;
|
||||||
|
if (aUnit == eCSSUnit_Percent) {
|
||||||
|
value.SetPercentValue(aValue);
|
||||||
|
} else {
|
||||||
|
value.SetFloatValue(aValue, aUnit);
|
||||||
|
}
|
||||||
|
value.AppendToString(aProperty, aResult, aSerialization);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
AppendNormalizedLengthPercentCalcToString(
|
||||||
|
const nsCSSValue& aValue,
|
||||||
|
nsCSSPropertyID aProperty,
|
||||||
|
nsAString& aResult,
|
||||||
|
nsCSSValue::Serialization aSerialization)
|
||||||
|
{
|
||||||
|
CSSValueLengthPercentCalcAccumulator accumulator;
|
||||||
|
if (!AccumulateCalcLengthPercentTerms(aValue, 1.0f, accumulator)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoTArray<CSSValueCalcLengthTerm, 9> serializedTerms;
|
||||||
|
if (!IsNearlyZero(accumulator.mPercent) || accumulator.mSawPercent) {
|
||||||
|
CSSValueCalcLengthTerm& term = *serializedTerms.AppendElement();
|
||||||
|
term.mUnit = eCSSUnit_Percent;
|
||||||
|
term.mValue = accumulator.mPercent;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const CSSValueCalcLengthTerm& term : accumulator.mLengths) {
|
||||||
|
if (IsNearlyZero(term.mValue)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
serializedTerms.AppendElement(term);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serializedTerms.IsEmpty()) {
|
||||||
|
CSSValueCalcLengthTerm& term = *serializedTerms.AppendElement();
|
||||||
|
term.mUnit = accumulator.mSawPercent ? eCSSUnit_Percent : eCSSUnit_Pixel;
|
||||||
|
term.mValue = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
aResult.AppendLiteral("calc(");
|
||||||
|
AppendSerializedCalcLeafValue(aProperty, aResult, aSerialization,
|
||||||
|
serializedTerms[0].mUnit,
|
||||||
|
serializedTerms[0].mValue);
|
||||||
|
|
||||||
|
for (uint32_t i = 1; i < serializedTerms.Length(); ++i) {
|
||||||
|
const CSSValueCalcLengthTerm& term = serializedTerms[i];
|
||||||
|
if (term.mValue < 0.0f) {
|
||||||
|
aResult.AppendLiteral(" - ");
|
||||||
|
AppendSerializedCalcLeafValue(aProperty, aResult, aSerialization,
|
||||||
|
term.mUnit, -term.mValue);
|
||||||
|
} else {
|
||||||
|
aResult.AppendLiteral(" + ");
|
||||||
|
AppendSerializedCalcLeafValue(aProperty, aResult, aSerialization,
|
||||||
|
term.mUnit, term.mValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aResult.Append(')');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1475,8 +1678,11 @@ nsCSSValue::AppendToString(nsCSSPropertyID aProperty, nsAString& aResult,
|
||||||
}
|
}
|
||||||
else if (IsCalcUnit()) {
|
else if (IsCalcUnit()) {
|
||||||
MOZ_ASSERT(GetUnit() == eCSSUnit_Calc, "unexpected unit");
|
MOZ_ASSERT(GetUnit() == eCSSUnit_Calc, "unexpected unit");
|
||||||
CSSValueSerializeCalcOps ops(aProperty, aResult, aSerialization);
|
if (!AppendNormalizedLengthPercentCalcToString(*this, aProperty, aResult,
|
||||||
css::SerializeCalc(*this, ops);
|
aSerialization)) {
|
||||||
|
CSSValueSerializeCalcOps ops(aProperty, aResult, aSerialization);
|
||||||
|
css::SerializeCalc(*this, ops);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (eCSSUnit_Integer == unit) {
|
else if (eCSSUnit_Integer == unit) {
|
||||||
aResult.AppendInt(GetIntValue(), 10);
|
aResult.AppendInt(GetIntValue(), 10);
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,25 @@ function parse2dMatrix(transformValue) {
|
||||||
|
|
||||||
div.remove();
|
div.remove();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
(function testNestedCalcSpecifiedSerialization() {
|
||||||
|
const div = appendTestNode();
|
||||||
|
const cases = [
|
||||||
|
["left", "calc(calc(20px) + calc(80px))", "calc(100px)"],
|
||||||
|
["left", "calc(calc(2) * calc(50px))", "calc(100px)"],
|
||||||
|
["left", "calc(calc(150px * 2 / 3))", "calc(100px)"],
|
||||||
|
["left", "calc(50px + calc(40%))", "calc(40% + 50px)"],
|
||||||
|
["border", "calc(calc(10px)) solid pink", "calc(10px) solid pink"],
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [property, input, expected] of cases) {
|
||||||
|
div.style.setProperty(property, input, "");
|
||||||
|
is(div.style.getPropertyValue(property), expected,
|
||||||
|
`${property} should canonicalize nested calc() serialization`);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.remove();
|
||||||
|
})();
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue