Bug 1616691 - Fix C++ side of <length-percentage> values. r=heycam

Differential Revision: https://phabricator.services.mozilla.com/D63398

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2020-02-21 00:46:50 +00:00
Родитель 9776b78db8
Коммит 1c8cc0fccb
6 изменённых файлов: 146 добавлений и 28 удалений

Просмотреть файл

@ -644,12 +644,7 @@ CSSCoord LengthPercentage::ToLengthInCSSPixels() const {
} }
bool LengthPercentage::ConvertsToPercentage() const { bool LengthPercentage::ConvertsToPercentage() const {
if (IsPercentage()) { return IsPercentage();
return true;
}
MOZ_ASSERT(IsLength() || !AsCalc().length.IsZero(),
"Should've been simplified to a percentage");
return false;
} }
float LengthPercentage::ToPercentage() const { float LengthPercentage::ToPercentage() const {
@ -673,11 +668,16 @@ bool LengthPercentage::IsDefinitelyZero() const {
if (IsPercentage()) { if (IsPercentage()) {
return AsPercentage()._0 == 0.0f; return AsPercentage()._0 == 0.0f;
} }
MOZ_ASSERT(!AsCalc().length.IsZero(), // calc() should've been simplified to a percentage.
"Should've been simplified to a percentage");
return false; return false;
} }
template <>
CSSCoord StyleCalcNode::ResolveToCSSPixels(CSSCoord aPercentageBasis) const;
template <>
void StyleCalcNode::ScaleLengthsBy(float);
CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const { CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const {
if (IsLength()) { if (IsLength()) {
return AsLength().ToCSSPixels(); return AsLength().ToCSSPixels();
@ -685,8 +685,7 @@ CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const {
if (IsPercentage()) { if (IsPercentage()) {
return AsPercentage()._0 * aPercentageBasis; return AsPercentage()._0 * aPercentageBasis;
} }
auto& calc = AsCalc(); return AsCalc().node.ResolveToCSSPixels(aPercentageBasis);
return calc.length.ToCSSPixels() + calc.percentage._0 * aPercentageBasis;
} }
template <typename T> template <typename T>
@ -700,12 +699,11 @@ CSSCoord LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter) const {
} }
template <typename T, typename U> template <typename T, typename U>
nscoord LengthPercentage::Resolve(T aPercentageGetter, nscoord LengthPercentage::Resolve(T aPercentageGetter, U aRounder) const {
U aPercentageRounder) const {
static_assert(std::is_same<decltype(aPercentageGetter()), nscoord>::value, static_assert(std::is_same<decltype(aPercentageGetter()), nscoord>::value,
"Should return app units"); "Should return app units");
static_assert( static_assert(
std::is_same<decltype(aPercentageRounder(1.0f)), nscoord>::value, std::is_same<decltype(aRounder(1.0f)), nscoord>::value,
"Should return app units"); "Should return app units");
if (ConvertsToLength()) { if (ConvertsToLength()) {
return ToLength(); return ToLength();
@ -715,11 +713,9 @@ nscoord LengthPercentage::Resolve(T aPercentageGetter,
} }
nscoord basis = aPercentageGetter(); nscoord basis = aPercentageGetter();
if (IsPercentage()) { if (IsPercentage()) {
return aPercentageRounder(basis * AsPercentage()._0); return aRounder(basis * AsPercentage()._0);
} }
auto& calc = AsCalc(); return AsCalc().node.Resolve(basis, aRounder);
return calc.length.ToAppUnits() +
aPercentageRounder(basis * calc.percentage._0);
} }
nscoord LengthPercentage::Resolve(nscoord aPercentageBasis) const { nscoord LengthPercentage::Resolve(nscoord aPercentageBasis) const {
@ -743,7 +739,7 @@ void LengthPercentage::ScaleLengthsBy(float aScale) {
AsLength().ScaleBy(aScale); AsLength().ScaleBy(aScale);
} }
if (IsCalc()) { if (IsCalc()) {
AsCalc().length.ScaleBy(aScale); AsCalc().node.ScaleLengthsBy(aScale);
} }
} }

Просмотреть файл

@ -3446,3 +3446,109 @@ bool StyleTransform::HasPercent() const {
} }
return false; return false;
} }
template <>
void StyleCalcNode::ScaleLengthsBy(float aScale) {
auto ScaleNode = [aScale](const StyleCalcNode& aNode) {
// This const_cast could be removed by generating more mut-casts, if
// needed.
const_cast<StyleCalcNode&>(aNode).ScaleLengthsBy(aScale);
};
switch (tag) {
case Tag::Leaf: {
auto& leaf = AsLeaf();
if (leaf.IsLength()) {
// This const_cast could be removed by generating more mut-casts, if
// needed.
const_cast<Length&>(leaf.AsLength()).ScaleBy(aScale);
}
break;
}
case Tag::Clamp: {
auto& clamp = AsClamp();
ScaleNode(*clamp.min);
ScaleNode(*clamp.center);
ScaleNode(*clamp.max);
break;
}
case Tag::MinMax: {
for (auto& child : AsMinMax()._0.AsSpan()) {
ScaleNode(child);
}
break;
}
case Tag::Sum: {
for (auto& child : AsSum().AsSpan()) {
ScaleNode(child);
}
break;
}
}
}
template <>
template <typename ResultT, typename PercentageConverter>
ResultT StyleCalcNode::ResolveInternal(ResultT aPercentageBasis,
PercentageConverter aConverter) const {
static_assert(std::is_same_v<decltype(aConverter(1.0f)), ResultT>);
static_assert(std::is_same_v<ResultT, nscoord> ||
std::is_same_v<ResultT, CSSCoord>);
switch (tag) {
case Tag::Leaf: {
auto& leaf = AsLeaf();
if (leaf.IsPercentage()) {
return aConverter(leaf.AsPercentage()._0 * aPercentageBasis);
}
if constexpr (std::is_same_v<ResultT, nscoord>) {
return leaf.AsLength().ToAppUnits();
} else {
return leaf.AsLength().ToCSSPixels();
}
}
case Tag::Clamp: {
auto& clamp = AsClamp();
auto min = clamp.min->ResolveInternal(aPercentageBasis, aConverter);
auto center = clamp.center->ResolveInternal(aPercentageBasis, aConverter);
auto max = clamp.max->ResolveInternal(aPercentageBasis, aConverter);
return std::max(min, std::min(center, max));
}
case Tag::MinMax: {
auto children = AsMinMax()._0.AsSpan();
StyleMinMaxOp op = AsMinMax()._1;
ResultT result = children[0].ResolveInternal(aPercentageBasis, aConverter);
for (auto& child : children.From(1)) {
ResultT candidate = child.ResolveInternal(aPercentageBasis, aConverter);
if (op == StyleMinMaxOp::Max) {
result = std::max(result, candidate);
} else {
result = std::min(result, candidate);
}
}
return result;
}
case Tag::Sum: {
ResultT result = 0;
for (auto& child : AsSum().AsSpan()) {
result += child.ResolveInternal(aPercentageBasis, aConverter);
}
return result;
}
}
MOZ_ASSERT_UNREACHABLE("Unknown calc node");
return 0;
}
template<>
CSSCoord StyleCalcNode::ResolveToCSSPixels(CSSCoord aBasis) const {
return ResolveInternal(aBasis, [](CSSCoord aPercent) { return aPercent; });
}
template<>
nscoord StyleCalcNode::Resolve(nscoord aBasis,
CoordPercentageRounder aRounder) const {
return ResolveInternal(aBasis, aRounder);
}

Просмотреть файл

@ -552,6 +552,7 @@ impl<'de> Deserialize<'de> for LengthPercentage {
/// The leaves of a `<length-percentage>` calc expression. /// The leaves of a `<length-percentage>` calc expression.
#[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, ToAnimatedZero, ToCss, ToResolvedValue)] #[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, ToAnimatedZero, ToCss, ToResolvedValue)]
#[allow(missing_docs)] #[allow(missing_docs)]
#[repr(u8)]
pub enum CalcLengthPercentageLeaf { pub enum CalcLengthPercentageLeaf {
Length(Length), Length(Length),
Percentage(Percentage), Percentage(Percentage),

Просмотреть файл

@ -54,9 +54,9 @@ pub enum GenericCalcNode<L> {
Leaf(L), Leaf(L),
/// A sum node, representing `a + b + c` where a, b, and c are the /// A sum node, representing `a + b + c` where a, b, and c are the
/// arguments. /// arguments.
Sum(Box<[GenericCalcNode<L>]>), Sum(crate::OwnedSlice<GenericCalcNode<L>>),
/// A `min` or `max` function. /// A `min` or `max` function.
MinMax(Box<[GenericCalcNode<L>]>, MinMaxOp), MinMax(crate::OwnedSlice<GenericCalcNode<L>>, MinMaxOp),
/// A `clamp()` function. /// A `clamp()` function.
Clamp { Clamp {
/// The minimum value. /// The minimum value.
@ -131,7 +131,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
fn map_children<L, O, F>( fn map_children<L, O, F>(
children: &[CalcNode<L>], children: &[CalcNode<L>],
map: &mut F, map: &mut F,
) -> Box<[CalcNode<O>]> ) -> crate::OwnedSlice<CalcNode<O>>
where where
L: CalcNodeLeaf, L: CalcNodeLeaf,
O: CalcNodeLeaf, O: CalcNodeLeaf,
@ -209,7 +209,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
pub fn simplify_and_sort_children(&mut self) { pub fn simplify_and_sort_children(&mut self) {
macro_rules! replace_self_with { macro_rules! replace_self_with {
($slot:expr) => {{ ($slot:expr) => {{
let dummy = Self::MinMax(Box::new([]), MinMaxOp::Max); let dummy = Self::MinMax(Default::default(), MinMaxOp::Max);
let result = mem::replace($slot, dummy); let result = mem::replace($slot, dummy);
mem::replace(self, result); mem::replace(self, result);
}}; }};
@ -315,7 +315,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
return replace_self_with!(&mut children_slot[0]); return replace_self_with!(&mut children_slot[0]);
} }
let mut children = mem::replace(children_slot, Box::new([])).into_vec(); let mut children = mem::replace(children_slot, Default::default()).into_vec();
if !sums_to_merge.is_empty() { if !sums_to_merge.is_empty() {
children.reserve(extra_kids - sums_to_merge.len()); children.reserve(extra_kids - sums_to_merge.len());
@ -347,7 +347,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
replace_self_with!(&mut children[0]); replace_self_with!(&mut children[0]);
} else { } else {
// Else put our simplified children back. // Else put our simplified children back.
mem::replace(children_slot, children.into_boxed_slice()); mem::replace(children_slot, children.into_boxed_slice().into());
} }
}, },
Self::Leaf(ref mut l) => { Self::Leaf(ref mut l) => {

Просмотреть файл

@ -397,8 +397,7 @@ impl CalcNode {
let arguments = input let arguments = input
.parse_comma_separated(|input| { .parse_comma_separated(|input| {
Self::parse_argument(context, input, expected_unit) Self::parse_argument(context, input, expected_unit)
})? })?;
.into_boxed_slice();
let op = match function { let op = match function {
MathFunction::Min => MinMaxOp::Min, MathFunction::Min => MinMaxOp::Min,
@ -406,7 +405,7 @@ impl CalcNode {
_ => unreachable!(), _ => unreachable!(),
}; };
Ok(Self::MinMax(arguments, op)) Ok(Self::MinMax(arguments.into(), op))
}, },
} }
}) })
@ -452,7 +451,7 @@ impl CalcNode {
Ok(if sum.len() == 1 { Ok(if sum.len() == 1 {
sum.drain(..).next().unwrap() sum.drain(..).next().unwrap()
} else { } else {
Self::Sum(sum.into_boxed_slice()) Self::Sum(sum.into_boxed_slice().into())
}) })
} }

Просмотреть файл

@ -271,6 +271,22 @@ renaming_overrides_prefixing = true
inline void ScaleBy(float); inline void ScaleBy(float);
""" """
"GenericCalcNode" = """
private:
template <typename ResultT, typename PercentageConverter>
ResultT ResolveInternal(ResultT aPercentageBasis,
PercentageConverter aPercentageConverter) const;
public:
CSSCoord ResolveToCSSPixels(CSSCoord aPercentageBasis) const;
using CoordPercentageRounder = nscoord(*)(float);
nscoord Resolve(nscoord aBasis, CoordPercentageRounder) const;
void ScaleLengthsBy(float);
"""
"LengthPercentageUnion" = """ "LengthPercentageUnion" = """
using Self = StyleLengthPercentageUnion; using Self = StyleLengthPercentageUnion;