зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
9776b78db8
Коммит
1c8cc0fccb
|
@ -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;
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче